/**
* Popover View
*
* Copyright 2012 Daniel Lupia�ez Casares <lupidan@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
**/
package com.smartandroid.sa.view;
import java.util.HashMap;
import java.util.Map;
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.widget.ImageView;
import android.widget.RelativeLayout;
public class PopoverView extends RelativeLayout implements OnTouchListener {
// ********************************************************************
// INTERFACES
// ********************************************************************
/**
* Interface to get information from the popover view. Use setDelegate to
* have access to this methods
*/
public static interface PopoverViewDelegate {
/**
* Called when the popover is going to show
*
* @param view
* The whole popover view
*/
void popoverViewWillShow(PopoverView view);
/**
* Called when the popover did show
*
* @param view
* The whole popover view
*/
void popoverViewDidShow(PopoverView view);
/**
* Called when the popover is going to be dismissed
*
* @param view
* The whole popover view
*/
void popoverViewWillDismiss(PopoverView view);
/**
* Called when the popover was dismissed
*
* @param view
* The whole popover view
*/
void popoverViewDidDismiss(PopoverView view);
}
private Context c;
// ********************************************************************
// STATIC MEMBERS
// ********************************************************************
/**
* Popover arrow points up. Integer to use with bit operators to tell the
* popover where the arrow should appear and from where the popover should
* appear
*/
public final static int PopoverArrowDirectionUp = 0x00000001;
/**
* Popover arrow points down. Integer to use with bit operators to tell the
* popover where the arrow should appear and from where the popover should
* appear
*/
public final static int PopoverArrowDirectionDown = 0x00000002;
/**
* Popover arrow points left. Integer to use with bit operators to tell the
* popover where the arrow should appear and from where the popover should
* appear
*/
public final static int PopoverArrowDirectionLeft = 0x00000004;
/**
* Popover arrow points right. Integer to use with bit operators to tell the
* popover where the arrow should appear and from where the popover should
* appear
*/
public final static int PopoverArrowDirectionRight = 0x00000008;
/**
* Popover arrow points any direction. Integer to use with bit operators to
* tell the popover where the arrow should appear and from where the popover
* should appear
*/
public final static int PopoverArrowDirectionAny = PopoverArrowDirectionUp
| PopoverArrowDirectionDown | PopoverArrowDirectionLeft
| PopoverArrowDirectionRight;
/**
* The default popover background drawable for all the popovers
*/
public static int defaultPopoverBackgroundDrawable;// =
// R.drawable.background_popover;
/**
* The default popover arrow up drawable for all the popovers
*/
public static int defaultPopoverArrowUpDrawable;// =
// R.drawable.icon_popover_arrow_up;
/**
* The default popover arrow down drawable for all the popovers
*/
public static int defaultPopoverArrowDownDrawable;// =
// R.drawable.icon_popover_arrow_down;
/**
* The default popover arrow left drawable for all the popovers
*/
public static int defaultPopoverArrowLeftDrawable;// =
// R.drawable.icon_popover_arrow_left;
/**
* The default popover arrow down drawable for all the popovers
*/
public static int defaultPopoverArrowRightDrawable;// =
// R.drawable.icon_popover_arrow_right;
// ********************************************************************
// STATIC METHODS
// ********************************************************************
/**
* Get the Rect frame for a view (relative to the Window of the application)
*
* @param v
* The view to get the rect from
* @return The rect of the view, relative to the application window
*/
public static Rect getFrameForView(View v) {
int location[] = new int[2];
v.getLocationOnScreen(location);
Rect viewRect = new Rect(location[0], location[1], location[0]
+ v.getWidth(), location[1] + v.getHeight());
return viewRect;
}
// ********************************************************************
// MEMBERS
// ********************************************************************
/**
* The delegate of the view
*/
private PopoverViewDelegate delegate;
/**
* The main popover containing the view we want to show
*/
private RelativeLayout popoverView;
/**
* The view group storing this popover. We need this so, when we dismiss the
* popover, we remove it from the view group
*/
private ViewGroup superview;
/**
* The content size for the view in the popover
*/
private Point contentSizeForViewInPopover = new Point(0, 0);
/**
* The real content size we will use (it considers the padding)
*/
private Point realContentSize = new Point(0, 0);
/**
* A hash containing
*/
private Map<Integer, Rect> possibleRects;
/**
* Whether the view is animating or not
*/
private boolean isAnimating = false;
/**
* The fade animation time in milliseconds
*/
private int fadeAnimationTime = 300;
/**
* The layout Rect, is the same as the superview rect
*/
private Rect popoverLayoutRect;
/**
* The popover background drawable
*/
private int popoverBackgroundDrawable;
/**
* The popover arrow up drawable
*/
private int popoverArrowUpDrawable;
/**
* The popover arrow down drawable
*/
private int popoverArrowDownDrawable;
/**
* The popover arrow left drawable
*/
private int popoverArrowLeftDrawable;
/**
* The popover arrow down drawable
*/
private int popoverArrowRightDrawable;
// ********************************************************************
// CONSTRUCTORS
// ********************************************************************
/**
* Constructor to create a popover with a popover view
*
* @param context
* The context where we should create the popover view
* @param layoutId
* The ID of the layout we want to put inside the popover
*/
public PopoverView(Context context, int layoutId) {
super(context);
this.c = context;
defaultPopoverBackgroundDrawable = getResources().getIdentifier(
"background_popover", "drawable", context.getPackageName());
// defaultPopoverBackgroundDrawable = R.drawable.background_popover;
/**
* The default popover arrow up drawable for all the popovers
*/
defaultPopoverArrowUpDrawable = getResources().getIdentifier(
"icon_popover_arrow_up", "drawable", context.getPackageName());
// defaultPopoverArrowUpDrawable = R.drawable.icon_popover_arrow_up;
/**
* The default popover arrow down drawable for all the popovers
*/
defaultPopoverArrowDownDrawable = getResources()
.getIdentifier("icon_popover_arrow_down", "drawable",
context.getPackageName());
// defaultPopoverArrowDownDrawable = R.drawable.icon_popover_arrow_down;
/**
* The default popover arrow left drawable for all the popovers
*/
defaultPopoverArrowLeftDrawable = getResources()
.getIdentifier("icon_popover_arrow_left", "drawable",
context.getPackageName());
// defaultPopoverArrowLeftDrawable = R.drawable.icon_popover_arrow_left;
/**
* The default popover arrow down drawable for all the popovers
*/
defaultPopoverArrowRightDrawable = getResources().getIdentifier(
"icon_popover_arrow_right", "drawable",
context.getPackageName());
// defaultPopoverArrowRightDrawable =
// R.drawable.icon_popover_arrow_right;
initPopoverView(inflate(context, layoutId, null));
}
/**
* Constructor to create a popover with a popover view
*
* @param context
* The context where we should create the popover view
* @param attrs
* Attribute set to init the view
* @param layoutId
* The ID of the layout we want to put inside the popover
*/
public PopoverView(Context context, AttributeSet attrs, int layoutId) {
super(context, attrs);
this.c = context;
defaultPopoverBackgroundDrawable = getResources().getIdentifier(
"background_popover", "drawable", context.getPackageName());
// defaultPopoverBackgroundDrawable = R.drawable.background_popover;
/**
* The default popover arrow up drawable for all the popovers
*/
defaultPopoverArrowUpDrawable = getResources().getIdentifier(
"icon_popover_arrow_up", "drawable", context.getPackageName());
// defaultPopoverArrowUpDrawable = R.drawable.icon_popover_arrow_up;
/**
* The default popover arrow down drawable for all the popovers
*/
defaultPopoverArrowDownDrawable = getResources()
.getIdentifier("icon_popover_arrow_down", "drawable",
context.getPackageName());
// defaultPopoverArrowDownDrawable = R.drawable.icon_popover_arrow_down;
/**
* The default popover arrow left drawable for all the popovers
*/
defaultPopoverArrowLeftDrawable = getResources()
.getIdentifier("icon_popover_arrow_left", "drawable",
context.getPackageName());
// defaultPopoverArrowLeftDrawable = R.drawable.icon_popover_arrow_left;
/**
* The default popover arrow down drawable for all the popovers
*/
defaultPopoverArrowRightDrawable = getResources().getIdentifier(
"icon_popover_arrow_right", "drawable",
context.getPackageName());
// defaultPopoverArrowRightDrawable =
// R.drawable.icon_popover_arrow_right;
initPopoverView(inflate(context, layoutId, null));
}
/**
* Constructor to create a popover with a popover view
*
* @param context
* The context where we should create the popover view
* @param attrs
* Attribute set to init the view
* @param defStyle
* The default style for this view
* @param layoutId
* The ID of the layout we want to put inside the popover
*/
public PopoverView(Context context, AttributeSet attrs, int defStyle,
int layoutId) {
super(context, attrs, defStyle);
this.c = context;
defaultPopoverBackgroundDrawable = getResources().getIdentifier(
"background_popover", "drawable", context.getPackageName());
// defaultPopoverBackgroundDrawable = R.drawable.background_popover;
/**
* The default popover arrow up drawable for all the popovers
*/
defaultPopoverArrowUpDrawable = getResources().getIdentifier(
"icon_popover_arrow_up", "drawable", context.getPackageName());
// defaultPopoverArrowUpDrawable = R.drawable.icon_popover_arrow_up;
/**
* The default popover arrow down drawable for all the popovers
*/
defaultPopoverArrowDownDrawable = getResources()
.getIdentifier("icon_popover_arrow_down", "drawable",
context.getPackageName());
// defaultPopoverArrowDownDrawable = R.drawable.icon_popover_arrow_down;
/**
* The default popover arrow left drawable for all the popovers
*/
defaultPopoverArrowLeftDrawable = getResources()
.getIdentifier("icon_popover_arrow_left", "drawable",
context.getPackageName());
// defaultPopoverArrowLeftDrawable = R.drawable.icon_popover_arrow_left;
/**
* The default popover arrow down drawable for all the popovers
*/
defaultPopoverArrowRightDrawable = getResources().getIdentifier(
"icon_popover_arrow_right", "drawable",
context.getPackageName());
// defaultPopoverArrowRightDrawable =
// R.drawable.icon_popover_arrow_right;
initPopoverView(inflate(context, layoutId, null));
}
/**
* Constructor to create a popover with a popover view
*
* @param context
* The context where we should create the popover view
* @param popoverView
* The inner view we want to show in a popover
*/
public PopoverView(Context context, View popoverView) {
super(context);
this.c = context;
defaultPopoverBackgroundDrawable = getResources().getIdentifier(
"background_popover", "drawable", context.getPackageName());
// defaultPopoverBackgroundDrawable = R.drawable.background_popover;
/**
* The default popover arrow up drawable for all the popovers
*/
defaultPopoverArrowUpDrawable = getResources().getIdentifier(
"icon_popover_arrow_up", "drawable", context.getPackageName());
// defaultPopoverArrowUpDrawable = R.drawable.icon_popover_arrow_up;
/**
* The default popover arrow down drawable for all the popovers
*/
defaultPopoverArrowDownDrawable = getResources()
.getIdentifier("icon_popover_arrow_down", "drawable",
context.getPackageName());
// defaultPopoverArrowDownDrawable = R.drawable.icon_popover_arrow_down;
/**
* The default popover arrow left drawable for all the popovers
*/
defaultPopoverArrowLeftDrawable = getResources()
.getIdentifier("icon_popover_arrow_left", "drawable",
context.getPackageName());
// defaultPopoverArrowLeftDrawable = R.drawable.icon_popover_arrow_left;
/**
* The default popover arrow down drawable for all the popovers
*/
defaultPopoverArrowRightDrawable = getResources().getIdentifier(
"icon_popover_arrow_right", "drawable",
context.getPackageName());
// defaultPopoverArrowRightDrawable =
// R.drawable.icon_popover_arrow_right;
initPopoverView(popoverView);
}
/**
* Constructor to create a popover with a popover view
*
* @param context
* The context where we should create the popover view
* @param attrs
* Attribute set to init the view
* @param popoverView
* The inner view we want to show in a popover
*/
public PopoverView(Context context, AttributeSet attrs, View popoverView) {
super(context, attrs);
this.c = context;
defaultPopoverBackgroundDrawable = getResources().getIdentifier(
"background_popover", "drawable", context.getPackageName());
// defaultPopoverBackgroundDrawable = R.drawable.background_popover;
/**
* The default popover arrow up drawable for all the popovers
*/
defaultPopoverArrowUpDrawable = getResources().getIdentifier(
"icon_popover_arrow_up", "drawable", context.getPackageName());
// defaultPopoverArrowUpDrawable = R.drawable.icon_popover_arrow_up;
/**
* The default popover arrow down drawable for all the popovers
*/
defaultPopoverArrowDownDrawable = getResources()
.getIdentifier("icon_popover_arrow_down", "drawable",
context.getPackageName());
// defaultPopoverArrowDownDrawable = R.drawable.icon_popover_arrow_down;
/**
* The default popover arrow left drawable for all the popovers
*/
defaultPopoverArrowLeftDrawable = getResources()
.getIdentifier("icon_popover_arrow_left", "drawable",
context.getPackageName());
// defaultPopoverArrowLeftDrawable = R.drawable.icon_popover_arrow_left;
/**
* The default popover arrow down drawable for all the popovers
*/
defaultPopoverArrowRightDrawable = getResources().getIdentifier(
"icon_popover_arrow_right", "drawable",
context.getPackageName());
// defaultPopoverArrowRightDrawable =
// R.drawable.icon_popover_arrow_right;
initPopoverView(popoverView);
}
/**
* Constructor to create a popover with a popover view
*
* @param context
* The context where we should create the popover view
* @param attrs
* Attribute set to init the view
* @param defStyle
* The default style for this view
* @param popoverView
* The inner view we want to show in a popover
*/
public PopoverView(Context context, AttributeSet attrs, int defStyle,
View popoverView) {
super(context, attrs, defStyle);
this.c = context;
defaultPopoverBackgroundDrawable = getResources().getIdentifier(
"background_popover", "drawable", context.getPackageName());
// defaultPopoverBackgroundDrawable = R.drawable.background_popover;
/**
* The default popover arrow up drawable for all the popovers
*/
defaultPopoverArrowUpDrawable = getResources().getIdentifier(
"icon_popover_arrow_up", "drawable", context.getPackageName());
// defaultPopoverArrowUpDrawable = R.drawable.icon_popover_arrow_up;
/**
* The default popover arrow down drawable for all the popovers
*/
defaultPopoverArrowDownDrawable = getResources()
.getIdentifier("icon_popover_arrow_down", "drawable",
context.getPackageName());
// defaultPopoverArrowDownDrawable = R.drawable.icon_popover_arrow_down;
/**
* The default popover arrow left drawable for all the popovers
*/
defaultPopoverArrowLeftDrawable = getResources()
.getIdentifier("icon_popover_arrow_left", "drawable",
context.getPackageName());
// defaultPopoverArrowLeftDrawable = R.drawable.icon_popover_arrow_left;
/**
* The default popover arrow down drawable for all the popovers
*/
defaultPopoverArrowRightDrawable = getResources().getIdentifier(
"icon_popover_arrow_right", "drawable",
context.getPackageName());
// defaultPopoverArrowRightDrawable =
// R.drawable.icon_popover_arrow_right;
initPopoverView(popoverView);
}
/**
* Init the popover view
*
* @param viewToEnclose
* The view we wan to insert inside the popover
*/
private void initPopoverView(View viewToEnclose) {
// Configure self
setBackgroundColor(0x00000000);
// setOnClickListener(this);
setOnTouchListener(this);
// Set initial drawables
popoverBackgroundDrawable = PopoverView.defaultPopoverBackgroundDrawable;
popoverArrowUpDrawable = PopoverView.defaultPopoverArrowUpDrawable;
popoverArrowDownDrawable = PopoverView.defaultPopoverArrowDownDrawable;
popoverArrowLeftDrawable = PopoverView.defaultPopoverArrowLeftDrawable;
popoverArrowRightDrawable = PopoverView.defaultPopoverArrowRightDrawable;
// Init the relative layout
popoverView = new RelativeLayout(getContext());
popoverView.setBackgroundDrawable(getResources().getDrawable(
popoverBackgroundDrawable));
popoverView.addView(viewToEnclose, LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT);
}
// ********************************************************************
// PRIVATE METHODS
// ********************************************************************
/**
* Add the popover to the view with a defined rect inside the popover
*
* @param insertRect
* The rect we want to insert the view
*/
private void addPopoverInRect(Rect insertRect) {
// Set layout params
LayoutParams insertParams = new LayoutParams(insertRect.width(),
insertRect.height());
insertParams.leftMargin = insertRect.left;
insertParams.topMargin = insertRect.top;
// Add the view
addView(popoverView, insertParams);
}
private void addArrow(Rect originRect, Integer arrowDirection) {
// Add arrow drawable
ImageView arrowImageView = new ImageView(getContext());
Drawable arrowDrawable = null;
int xPos = 0;
int arrowWidth = 0;
int yPos = 0;
int arrowHeight = 0;
// Get correct drawable, and get Width, Height, Xpos and yPos depending
// on the selected arrow direction
if (arrowDirection == PopoverView.PopoverArrowDirectionUp) {
arrowDrawable = getResources().getDrawable(popoverArrowUpDrawable);
arrowWidth = arrowDrawable.getIntrinsicWidth();
arrowHeight = arrowDrawable.getIntrinsicHeight();
xPos = originRect.centerX() - (arrowWidth / 2)
- popoverLayoutRect.left;
yPos = originRect.bottom - popoverLayoutRect.top;
} else if (arrowDirection == PopoverView.PopoverArrowDirectionDown) {
arrowDrawable = getResources()
.getDrawable(popoverArrowDownDrawable);
arrowWidth = arrowDrawable.getIntrinsicWidth();
arrowHeight = arrowDrawable.getIntrinsicHeight();
xPos = originRect.centerX() - (arrowWidth / 2)
- popoverLayoutRect.left;
yPos = originRect.top - arrowHeight - popoverLayoutRect.top;
} else if (arrowDirection == PopoverView.PopoverArrowDirectionLeft) {
arrowDrawable = getResources()
.getDrawable(popoverArrowLeftDrawable);
arrowWidth = arrowDrawable.getIntrinsicWidth();
arrowHeight = arrowDrawable.getIntrinsicHeight();
xPos = originRect.right - popoverLayoutRect.left;
yPos = originRect.centerY() - (arrowHeight / 2)
- popoverLayoutRect.top;
} else if (arrowDirection == PopoverView.PopoverArrowDirectionRight) {
arrowDrawable = getResources().getDrawable(
popoverArrowRightDrawable);
arrowWidth = arrowDrawable.getIntrinsicWidth();
arrowHeight = arrowDrawable.getIntrinsicHeight();
xPos = originRect.left - arrowWidth - popoverLayoutRect.left;
yPos = originRect.centerY() - (arrowHeight / 2)
- popoverLayoutRect.top;
}
// Set drawable
arrowImageView.setImageDrawable(arrowDrawable);
// Init layout params
LayoutParams arrowParams = new LayoutParams(arrowWidth, arrowHeight);
arrowParams.leftMargin = xPos;
arrowParams.topMargin = yPos;
// add view :)
addView(arrowImageView, arrowParams);
}
/**
* Calculates the rect for showing the view with Arrow Up
*
* @param originRect
* The origin rect
* @return The calculated rect to show the view
*/
private Rect getRectForArrowUp(Rect originRect) {
// Get available space
int xAvailable = popoverLayoutRect.width();
if (xAvailable < 0)
xAvailable = 0;
int yAvailable = popoverLayoutRect.height()
- (originRect.bottom - popoverLayoutRect.top);
if (yAvailable < 0)
yAvailable = 0;
// Get final width and height
int finalX = xAvailable;
if ((realContentSize.x > 0) && (realContentSize.x < finalX))
finalX = realContentSize.x;
int finalY = yAvailable;
if ((realContentSize.y > 0) && (realContentSize.y < finalY))
finalY = realContentSize.y;
// Get final origin X and Y
int originX = (originRect.centerX() - popoverLayoutRect.left)
- (finalX / 2);
if (originX < 0)
originX = 0;
else if (originX + finalX > popoverLayoutRect.width())
originX = popoverLayoutRect.width() - finalX;
int originY = (originRect.bottom - popoverLayoutRect.top);
// Create rect
Rect finalRect = new Rect(originX, originY, originX + finalX, originY
+ finalY);
// And return
return finalRect;
}
/**
* Calculates the rect for showing the view with Arrow Down
*
* @param originRect
* The origin rect
* @return The calculated rect to show the view
*/
private Rect getRectForArrowDown(Rect originRect) {
// Get available space
int xAvailable = popoverLayoutRect.width();
if (xAvailable < 0)
xAvailable = 0;
int yAvailable = (originRect.top - popoverLayoutRect.top);
if (yAvailable < 0)
yAvailable = 0;
// Get final width and height
int finalX = xAvailable;
if ((realContentSize.x > 0) && (realContentSize.x < finalX))
finalX = realContentSize.x;
int finalY = yAvailable;
if ((realContentSize.y > 0) && (realContentSize.y < finalY))
finalY = realContentSize.y;
// Get final origin X and Y
int originX = (originRect.centerX() - popoverLayoutRect.left)
- (finalX / 2);
if (originX < 0)
originX = 0;
else if (originX + finalX > popoverLayoutRect.width())
originX = popoverLayoutRect.width() - finalX;
int originY = (originRect.top - popoverLayoutRect.top) - finalY;
// Create rect
Rect finalRect = new Rect(originX, originY, originX + finalX, originY
+ finalY);
// And return
return finalRect;
}
/**
* Calculates the rect for showing the view with Arrow Right
*
* @param originRect
* The origin rect
* @return The calculated rect to show the view
*/
private Rect getRectForArrowRight(Rect originRect) {
// Get available space
int xAvailable = (originRect.left - popoverLayoutRect.left);
if (xAvailable < 0)
xAvailable = 0;
int yAvailable = popoverLayoutRect.height();
if (yAvailable < 0)
yAvailable = 0;
// Get final width and height
int finalX = xAvailable;
if ((realContentSize.x > 0) && (realContentSize.x < finalX))
finalX = realContentSize.x;
int finalY = yAvailable;
if ((realContentSize.y > 0) && (realContentSize.y < finalY))
finalY = realContentSize.y;
// Get final origin X and Y
int originX = (originRect.left - popoverLayoutRect.left) - finalX;
int originY = (originRect.centerY() - popoverLayoutRect.top)
- (finalY / 2);
if (originY < 0)
originY = 0;
else if (originY + finalY > popoverLayoutRect.height())
originY = popoverLayoutRect.height() - finalY;
// Create rect
Rect finalRect = new Rect(originX, originY, originX + finalX, originY
+ finalY);
// And return
return finalRect;
}
/**
* Calculates the rect for showing the view with Arrow Left
*
* @param originRect
* The origin rect
* @return The calculated rect to show the view
*/
private Rect getRectForArrowLeft(Rect originRect) {
// Get available space
int xAvailable = popoverLayoutRect.width()
- (originRect.right - popoverLayoutRect.left);
if (xAvailable < 0)
xAvailable = 0;
int yAvailable = popoverLayoutRect.height();
if (yAvailable < 0)
yAvailable = 0;
// Get final width and height
int finalX = xAvailable;
if ((realContentSize.x > 0) && (realContentSize.x < finalX))
finalX = realContentSize.x;
int finalY = yAvailable;
if ((realContentSize.y > 0) && (realContentSize.y < finalY))
finalY = realContentSize.y;
// Get final origin X and Y
int originX = (originRect.right - popoverLayoutRect.left);
int originY = (originRect.centerY() - popoverLayoutRect.top)
- (finalY / 2);
if (originY < 0)
originY = 0;
else if (originY + finalY > popoverLayoutRect.height())
originY = popoverLayoutRect.height() - finalY;
// Create rect
Rect finalRect = new Rect(originX, originY, originX + finalX, originY
+ finalY);
// And return
return finalRect;
}
/**
* Add available rects for each selected arrow direction
*
* @param originRect
* The rect where the popover will appear from
* @param arrowDirections
* The bit mask for the possible arrow directions
*/
private void addAvailableRects(Rect originRect, int arrowDirections) {
// Get popover rects for the available directions
possibleRects = new HashMap<Integer, Rect>();
if ((arrowDirections & PopoverView.PopoverArrowDirectionUp) != 0) {
possibleRects.put(PopoverView.PopoverArrowDirectionUp,
getRectForArrowUp(originRect));
}
if ((arrowDirections & PopoverView.PopoverArrowDirectionDown) != 0) {
possibleRects.put(PopoverView.PopoverArrowDirectionDown,
getRectForArrowDown(originRect));
}
if ((arrowDirections & PopoverView.PopoverArrowDirectionRight) != 0) {
possibleRects.put(PopoverView.PopoverArrowDirectionRight,
getRectForArrowRight(originRect));
}
if ((arrowDirections & PopoverView.PopoverArrowDirectionLeft) != 0) {
possibleRects.put(PopoverView.PopoverArrowDirectionLeft,
getRectForArrowLeft(originRect));
}
}
/**
* Get the best available rect (bigger area)
*
* @return The Integer key to get the Rect from posibleRects
* (PopoverArrowDirectionUp
* ,PopoverArrowDirectionDown,PopoverArrowDirectionRight or
* PopoverArrowDirectionLeft)
*/
private Integer getBestRect() {
// Get the best one (bigger area)
Integer best = null;
for (Integer arrowDir : possibleRects.keySet()) {
if (best == null) {
best = arrowDir;
} else {
Rect bestRect = possibleRects.get(best);
Rect checkRect = possibleRects.get(arrowDir);
if ((bestRect.width() * bestRect.height()) < (checkRect.width() * checkRect
.height()))
best = arrowDir;
}
}
return best;
}
// ********************************************************************
// GETTERS AND SETTERS
// ********************************************************************
/**
* Gets the current fade animation time
*
* @return The fade animation time, in milliseconds
*/
public int getFadeAnimationTime() {
return fadeAnimationTime;
}
/**
* Sets the fade animation time
*
* @param fadeAnimationTime
* The time in milliseconds
*/
public void setFadeAnimationTime(int fadeAnimationTime) {
this.fadeAnimationTime = fadeAnimationTime;
}
/**
* Get the content size for view in popover
*
* @return The point with the content size
*/
public Point getContentSizeForViewInPopover() {
return contentSizeForViewInPopover;
}
/**
* Sets the content size for the view in a popover, if point is (0,0) the
* popover will full the screen
*
* @param contentSizeForViewInPopover
*/
public void setContentSizeForViewInPopover(Point contentSizeForViewInPopover) {
this.contentSizeForViewInPopover = contentSizeForViewInPopover;
// Save the real content size
realContentSize = new Point(contentSizeForViewInPopover);
realContentSize.x += popoverView.getPaddingLeft()
+ popoverView.getPaddingRight();
realContentSize.y += popoverView.getPaddingTop()
+ popoverView.getPaddingBottom();
}
/**
* Gets the current delegate
*
* @return The current delegate
*/
public PopoverViewDelegate getDelegate() {
return delegate;
}
/**
* Sets the popover delegate
*
* @param delegate
* The new popover delegate
*/
public void setDelegate(PopoverViewDelegate delegate) {
this.delegate = delegate;
}
/**
* @return Current background drawable
*/
public int getPopoverBackgroundDrawable() {
return popoverBackgroundDrawable;
}
/**
* @param popoverBackgroundDrawable
* The new background drawable
*/
public void setPopoverBackgroundDrawable(int popoverBackgroundDrawable) {
this.popoverBackgroundDrawable = popoverBackgroundDrawable;
}
/**
* @return Current arrow up drawable
*/
public int getPopoverArrowUpDrawable() {
return popoverArrowUpDrawable;
}
/**
* @param popoverArrowUpDrawable
* The new arrow up drawable
*/
public void setPopoverArrowUpDrawable(int popoverArrowUpDrawable) {
this.popoverArrowUpDrawable = popoverArrowUpDrawable;
}
/**
* @return Current arrow down drawable
*/
public int getPopoverArrowDownDrawable() {
return popoverArrowDownDrawable;
}
/**
* @param popoverArrowDownDrawable
* The new arrow down drawable
*/
public void setPopoverArrowDownDrawable(int popoverArrowDownDrawable) {
this.popoverArrowDownDrawable = popoverArrowDownDrawable;
}
/**
* @return Current arrow left drawable
*/
public int getPopoverArrowLeftDrawable() {
return popoverArrowLeftDrawable;
}
/**
* @param popoverArrowLeftDrawable
* The new arrow left drawable
*/
public void setPopoverArrowLeftDrawable(int popoverArrowLeftDrawable) {
this.popoverArrowLeftDrawable = popoverArrowLeftDrawable;
}
/**
* @return Current arrow right drawable
*/
public int getPopoverArrowRightDrawable() {
return popoverArrowRightDrawable;
}
/**
* @param popoverArrowRightDrawable
* The new arrow right drawable
*/
public void setPopoverArrowRightDrawable(int popoverArrowRightDrawable) {
this.popoverArrowRightDrawable = popoverArrowRightDrawable;
}
// ********************************************************************
// PUBLIC METHODS
// ********************************************************************
/**
* This method shows a popover in a ViewGroup, from an origin rect (relative
* to the Application Window)
*
* @param group
* The group we want to insert the popup. Normally a Relative
* Layout so it can stand on top of everything
* @param originRect
* The rect we want the popup to appear from (relative to the
* Application Window!)
* @param arrowDirections
* The mask of bits to tell in which directions we want the
* popover to be shown
* @param animated
* Whether is animated, or not
*/
public void showPopoverFromRectInViewGroup(ViewGroup group,
Rect originRect, int arrowDirections, boolean animated) {
// First, tell delegate we will show
if (delegate != null)
delegate.popoverViewWillShow(this);
// Save superview
superview = group;
// First, add the view to the view group. The popover will cover the
// whole area
android.view.ViewGroup.LayoutParams insertParams = new android.view.ViewGroup.LayoutParams(
android.view.ViewGroup.LayoutParams.FILL_PARENT,
android.view.ViewGroup.LayoutParams.FILL_PARENT);
group.addView(this, insertParams);
// Now, save rect for the layout (is the same as the superview)
popoverLayoutRect = PopoverView.getFrameForView(superview);
// Add available rects
addAvailableRects(originRect, arrowDirections);
// Get best rect
Integer best = getBestRect();
// Add popover
Rect bestRect = possibleRects.get(best);
addPopoverInRect(bestRect);
// Add arrow image
addArrow(originRect, best);
// If we don't want animation, just tell the delegate
if (!animated) {
// Tell delegate we did show
if (delegate != null)
delegate.popoverViewDidShow(this);
}
// If we want animation, animate it!
else {
// Continue only if we are not animating
if (!isAnimating) {
// Create alpha animation, with its listener
AlphaAnimation animation = new AlphaAnimation(0.0f, 1.0f);
animation.setDuration(fadeAnimationTime);
animation.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
// Nothing to do here
}
@Override
public void onAnimationRepeat(Animation animation) {
// Nothing to do here
}
@Override
public void onAnimationEnd(Animation animation) {
// End animation
isAnimating = false;
// Tell delegate we did show
if (delegate != null)
delegate.popoverViewDidShow(PopoverView.this);
}
});
// Start animation
isAnimating = true;
startAnimation(animation);
}
}
}
/**
* Dismiss the current shown popover
*
* @param animated
* Whether it should be dismissed animated or not
*/
public void dissmissPopover(boolean animated) {
// Tell delegate we will dismiss
if (delegate != null)
delegate.popoverViewWillDismiss(PopoverView.this);
// If we don't want animation
if (!animated) {
// Just remove views
popoverView.removeAllViews();
removeAllViews();
superview.removeView(this);
// Tell delegate we did dismiss
if (delegate != null)
delegate.popoverViewDidDismiss(PopoverView.this);
} else {
// Continue only if there is not an animation in progress
if (!isAnimating) {
// Create alpha animation, with its listener
AlphaAnimation animation = new AlphaAnimation(1.0f, 0.0f);
animation.setDuration(fadeAnimationTime);
animation.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
// Nothing to do here
}
@Override
public void onAnimationRepeat(Animation animation) {
// Nothing to do here
}
@Override
public void onAnimationEnd(Animation animation) {
// Remove the view
popoverView.removeAllViews();
removeAllViews();
PopoverView.this.superview.removeView(PopoverView.this);
// End animation
isAnimating = false;
// Tell delegate we did dismiss
if (delegate != null)
delegate.popoverViewDidDismiss(PopoverView.this);
}
});
// Start animation
isAnimating = true;
startAnimation(animation);
}
}
}
// ********************************************************************
// ON TOUCH LISTENER
// ********************************************************************
@Override
public boolean onTouch(View v, MotionEvent event) {
// If we touched over the background popover view (this)
if ((!isAnimating) && (v == this)) {
dissmissPopover(true);
}
return true;
}
}