Page 1 of 1

PopupMenu, ContextMenu and Custom PopupWindow, all in one

#1 EndLessMind  Icon User is offline

  • These are the droids you're looking for
  • member icon

Reputation: 194
  • View blog
  • Posts: 1,099
  • Joined: 13-March 09

Posted 08 December 2012 - 04:54 PM

Hi everyone! EndLessMind here with another great tutorial!
In this tutorial, we are going to make a PopupMenu, ContextMenu and Custom PopupWindow at once.


Introduction
Ever wanted a popup-menu that expands from a view, or a Popup-window that's easy to use?
Well, now i'm going to share how to do it.

In native Android, there is a PopupWindow, but it's not really easy to use it.
By creating some fairly simple code, we can make use if this function with only a few lines of code.


Creating the project
Okey, so lets start out with creating the project

Lets first create a new Android project and name it "com.example.mywindow"
and the build target for Android 2.1, and next set the following:
Application name: Tutorial Sound Custom Window
Package name: com.example.mywindow
Create Activity (Checked): MainActivity
Then press Finish.


Making use of the PopupWindow
Okay, so now we will be making a class named PopupWindows
In that class, we'll add this code:
package com.example.mywindow;

import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;

import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.View.OnTouchListener;
import android.widget.PopupWindow;

import android.content.Context;

/**
 *  @author Pontus Holmberg (EndLessMind)
 *  Email: the_mr_hb@hotmail.com
 **/
public class PopupWindows {
	protected Context mContext;
	public PopupWindow mWindow;
	protected View mRootView;
	protected Drawable mBackground = null;
	protected WindowManager mWindowManager;
	
	/**
	 * Constructor.
	 * 
	 * @param context Context
	 */
	public PopupWindows(Context context) {
		mContext	= context;
		mWindow 	= new PopupWindow(context);
		mwindow.setBackgroundDrawable(new BitmapDrawable());
		mwindow.setTouchInterceptor(new OnTouchListener() {
			public boolean onTouch(View v, MotionEvent event) {
				if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
					mwindow.dismiss();
					
					return true;
				}
				
				return false;
			}
		});

		mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
	}
	
	/**
	 * On dismiss
	 */
	protected void onDismiss() {		
	}
	
	/**
	 * On show
	 */
	protected void onShow() {		
	}


	/**
	 * On pre show
	 */
	protected void preShow() {
		if (mRootView == null) 
			throw new IllegalStateException("setContentView was not called with a view to display.");
	
		onShow();

	//	if (mBackground == null) 
	//		mwindow.setBackgroundDrawable(new BitmapDrawable());
	//else 
	//		mwindow.setBackgroundDrawable(new BitmapDrawable());

		mwindow.setWidth(WindowManager.LayoutParams.WRAP_CONTENT);
		mwindow.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
//		mwindow.setTouchable(true);
	//	mwindow.setFocusable(true);
	//	mwindow.setOutsideTouchable(true);

		mwindow.setContentView(mRootView);
	}

	/**
	 * Set background drawable.
	 * 
	 * @param background Background drawable
	 */
	public void setBackgroundDrawable(Drawable background) {
		mwindow.setBackgroundDrawable(background);
	}

	/**
	 * Set content view.
	 * 
	 * @param root Root view
	 */
	public void setContentView(View root) {
		mRootView = root;
		
		mwindow.setContentView(root);
	}

	/**
	 * Set content view.
	 * 
	 * @param layoutResID Resource id
	 */
	public void setContentView(int layoutResID) {
		LayoutInflater inflator = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		
		setContentView(inflator.inflate(layoutResID, null));
	}

	/**
	 * Set listener on window dismissed.
	 * 
	 * @param listener
	 */
	public void setOnDismissListener(Popupwindow.OnDismissListener listener) {
		mwindow.setOnDismissListener(listener);  
	}

	/**
	 * Dismiss the popup window.
	 */
	public void dismiss() {
		mwindow.dismiss();
	}
}


All this code dose, is simplifying the usage of the native Popupwindow.
We'll come back to this later.

A Quick re-action?
Now it's time to make a new class, and we are going to name it QuickAction
We'll add this code to it:
package com.example.mywindow;

import android.content.Context;

import android.graphics.Rect;
import android.graphics.drawable.Drawable;

import android.widget.ImageView;
import android.widget.TextView;
import android.widget.ScrollView;
import android.widget.RelativeLayout;
import android.widget.Popupwindow.OnDismissListener;

import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.onclickListener;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewGroup;

import java.util.List;
import java.util.ArrayList;

/**
 *  @author Pontus Holmberg (EndLessMind)
 *  Email: the_mr_hb@hotmail.com
 **/


public class QuickAction extends PopupWindows implements OnDismissListener {
	private View mRootView;
	private ImageView mArrowUp;
	private ImageView mArrowDown;
	private LayoutInflater mInflater;
	private ViewGroup mTrack;
	private ScrollView mScroller;
	private OnActionItemClickListener mItemClickListener;
	private OnDismissListener mDismissListener;
	
	private List<ActionItem> actionItems = new ArrayList<ActionItem>();
	
	private boolean mDidAction;
	public boolean isDismissed = false;
	
	private int mChildPos;
    private int mInsertPos;
    private int mAnimStyle;
    private int mOrientation;
    private int rootWidth=0;
    
    public static final int HORIZONTAL = 0;
    public static final int VERTICAL = 1;
    
    public static final int ANIM_GROW_FROM_LEFT = 1;
	public static final int ANIM_GROW_FROM_RIGHT = 2;
	public static final int ANIM_GROW_FROM_CENTER = 3;
	public static final int ANIM_REFLECT = 4;
	public static final int ANIM_AUTO = 5;
	public static View baseView = null;
    /**
     * Constructor for default vertical layout
     * 
     * @param context  Context
     */
    public QuickAction(Context context) {
        this(context, VERTICAL);
    }

    /**
     * Constructor allowing orientation override
     * 
     * @param context    Context
     * @param orientation Layout orientation, can be vartical or horizontal
     */
    public QuickAction(Context context, int orientation) {
        super(context);
        
        mOrientation = orientation;
        
        mInflater 	 = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        if (mOrientation == HORIZONTAL) {
            setRootViewId(R.layout.popup_horizontal);
        } else {
            setRootViewId(R.layout.popup_vertical);
        }

        mAnimStyle 	= ANIM_AUTO;
        mChildPos 	= 0;
    }

    /**
     * Get action item at an index
     * 
     * @param index  Index of item (position from callback)
     * 
     * @return  Action Item at the position
     */
    public ActionItem getActionItem(int index) {
        return actionItems.get(index);
    }
    
    public View GetBaseView() {
    	return baseView;
    }
	/**
	 * Set root view.
	 * 
	 * @param id Layout resource id
	 */
	public void setRootViewId(int id) {
	//	setOutsideTouchable(true);
		mRootView	= (ViewGroup) mInflater.inflate(id, null);
		mTrack 		= (ViewGroup) mRootView.findViewById(R.id.tracks);

		mArrowDown 	= (ImageView) mRootView.findViewById(R.id.arrow_down);
		mArrowUp 	= (ImageView) mRootView.findViewById(R.id.arrow_up);

		mScroller	= (ScrollView) mRootView.findViewById(R.id.scroller);
		
		//This was previously defined on show() method, moved here to prevent force close that occured
		//when tapping fastly on a view to show quickaction dialog.
		//thanks to zammbi (github.com/zammbi)
		mRootView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
		setContentView(mRootView);
	}
	
	/**
	 * Set animation style
	 * 
	 * @param mAnimStyle animation style, default is set to ANIM_AUTO
	 */
	public void setAnimStyle(int mAnimStyle) {
		this.mAnimStyle = mAnimStyle;
	}
	
	/**
	 * Set listener for action item clicked.
	 * 
	 * @param listener Listener
	 */
	public void setOnActionItemClickListener(OnActionItemClickListener listener) {
		mItemClickListener = listener;
	}
	
	/**
	 * Add action item
	 * 
	 * @param action  {@link ActionItem}
	 */
	public void addActionItem(ActionItem action) {
		actionItems.add(action);
		
		String title 	= action.getTitle();
		Drawable icon 	= action.getIcon();
		
		View container;
		
		if (mOrientation == HORIZONTAL) {
            container = mInflater.inflate(R.layout.action_item_horizontal, null);
        } else {
            container = mInflater.inflate(R.layout.action_item_vertical, null);
        }
		
		ImageView img 	= (ImageView) container.findViewById(R.id.iv_icon);
		TextView text 	= (TextView) container.findViewById(R.id.tv_title);
		
		if (icon != null) {
			img.setImageDrawable(icon);
		} else {
			img.setVisibility(View.GONE);
		}
		
		if (title != null) {
			text.setText(title);
		} else {
			text.setVisibility(View.GONE);
		}
		
		final int pos 		=  mChildPos;
		final int actionId 	= action.getActionId();
		
		container.setonclickListener(new onclickListener() {
			public void onclick(View v) {
				if (mItemClickListener != null) {
                    mItemClickListener.onItemClick(QuickAction.this, pos, actionId);
                }
				
                if (!getActionItem(pos).isSticky()) {  
                	mDidAction = true;
                	
                    dismiss();
                }
			}
		});
		
		container.setFocusable(true);
		container.setClickable(true);
			 
		if (mOrientation == HORIZONTAL && mChildPos != 0) {
            View separator = mInflater.inflate(R.layout.horiz_separator, null);
            
            RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.FILL_PARENT);
            
            separator.setLayoutParams(params);
            separator.setPadding(5, 0, 5, 0);
            
            mTrack.addView(separator, mInsertPos);
            
            mInsertPos++;
        }
		
		mTrack.addView(container, mInsertPos);
		
		mChildPos++;
		mInsertPos++;
	}
	
	/**
	 * Show quickaction popup. Popup is automatically positioned, on top or bottom of anchor view.
	 * 
	 */
	public void show (View anchor) {
		preShow();
		this.baseView = anchor;
		int xPos, yPos, arrowPos;
		
		mDidAction 			= false;
		
		int[] location 		= new int[2];
	
		anchor.getLocationOnScreen(location);

		Rect anchorRect 	= new Rect(location[0], location[1], location[0] + anchor.getWidth(), location[1] 
		                	+ anchor.getHeight());

		//mRootView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
		
		mRootView.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
	
		int rootHeight 		= mRootView.getMeasuredHeight();
		
		if (rootWidth == 0) {
			rootWidth		= mRootView.getMeasuredWidth();
		}
		
		int screenWidth 	= mWindowManager.getDefaultDisplay().getWidth();
		int screenHeight	= mWindowManager.getDefaultDisplay().getHeight();
		
		//automatically get X coord of popup (top left)
		if ((anchorRect.left + rootWidth) > screenWidth) {
			xPos 		= anchorRect.left - (rootWidth-anchor.getWidth());			
			xPos 		= (xPos < 0) ? 0 : xPos;
			
			arrowPos 	= anchorRect.centerX()-xPos;
			
		} else {
			if (anchor.getWidth() > rootWidth) {
				xPos = anchorRect.centerX() - (rootWidth/2);
			} else {
				xPos = anchorRect.left;
			}
			
			arrowPos = anchorRect.centerX()-xPos;
		}
		
		int dyTop			= anchorRect.top;
		int dyBottom		= screenHeight - anchorRect.bottom;

		boolean onTop		= (dyTop > dyBottom) ? true : false;

		if (onTop) {
			if (rootHeight > dyTop) {
				yPos 			= 15;
				LayoutParams l 	= mScroller.getLayoutParams();
				l.height		= dyTop - anchor.getHeight();
			} else {
				yPos = anchorRect.top - rootHeight;
			}
		} else {
			yPos = anchorRect.bottom;
			
			if (rootHeight > dyBottom) { 
				LayoutParams l 	= mScroller.getLayoutParams();
				l.height		= dyBottom;
			}
		}
		
		showArrow(((onTop) ? R.id.arrow_down : R.id.arrow_up), arrowPos);
		
		setAnimationStyle(screenWidth, anchorRect.centerX(), onTop);
		
		mwindow.showAtLocation(anchor, Gravity.NO_GRAVITY, xPos, yPos);
	}
	
	/**
	 * Set animation style
	 * 
	 * @param screenWidth screen width
	 * @param requestedX distance from left edge
	 * @param onTop flag to indicate where the popup should be displayed. Set TRUE if displayed on top of anchor view
	 * 		  and vice versa
	 */
	private void setAnimationStyle(int screenWidth, int requestedX, boolean onTop) {
		int arrowPos = requestedX - mArrowUp.getMeasuredWidth()/2;

		switch (mAnimStyle) {
		case ANIM_GROW_FROM_LEFT:
			mwindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Left : R.style.Animations_PopDownMenu_Left);
			break;
					
		case ANIM_GROW_FROM_RIGHT:
			mwindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Right : R.style.Animations_PopDownMenu_Right);
			break;
					
		case ANIM_GROW_FROM_CENTER:
			mwindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Center : R.style.Animations_PopDownMenu_Center);
		break;
			
		case ANIM_REFLECT:
			mwindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Reflect : R.style.Animations_PopDownMenu_Reflect);
		break;
		
		case ANIM_AUTO:
			if (arrowPos <= screenWidth/4) {
				mwindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Left : R.style.Animations_PopDownMenu_Left);
			} else if (arrowPos > screenWidth/4 && arrowPos < 3 * (screenWidth/4)) {
				mwindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Center : R.style.Animations_PopDownMenu_Center);
			} else {
				mwindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Right : R.style.Animations_PopDownMenu_Right);
			}
					
			break;
		}
	}
	
	/**
	 * Show arrow
	 * 
	 * @param whichArrow arrow type resource id
	 * @param requestedX distance from left screen
	 */
	private void showArrow(int whichArrow, int requestedX) {
        final View showArrow = (whichArrow == R.id.arrow_up) ? mArrowUp : mArrowDown;
        final View hideArrow = (whichArrow == R.id.arrow_up) ? mArrowDown : mArrowUp;

        final int arrowWidth = mArrowUp.getMeasuredWidth();

        showArrow.setVisibility(View.VISIBLE);
        
        ViewGroup.MarginLayoutParams param = (ViewGroup.MarginLayoutParams)showArrow.getLayoutParams();
       
        param.leftMargin = requestedX - arrowWidth / 2;
        
        hideArrow.setVisibility(View.INVISIBLE);
    }
	
	/**
	 * Set listener for window dismissed. This listener will only be fired if the quicakction dialog is dismissed
	 * by clicking outside the dialog or clicking on sticky item.
	 */
	public void setOnDismissListener(QuickAction.OnDismissListener listener) {
		setOnDismissListener(this);
		
		mDismissListener = listener;
	}
	
	@Override
	public void onDismiss() {
		if (!mDidAction && mDismissListener != null) {
			isDismissed = true;
			Log.d("Qick", "Dismissed-inside");
			mDismissListener.onDismiss();
		}
	}
	
	/**
	 * Listener for item click
	 *
	 */
	public interface OnActionItemClickListener {
		public abstract void onItemClick(QuickAction source, int pos, int actionId);
	}
	
	/**
	 * Listener for window dismiss
	 * 
	 */
	public interface OnDismissListener {
		public abstract void onDismiss();
	}
}


So, i guess you are getting a bunch of error right now. Don't worry, we'll get there.
This class uses the PopupWindows-class to create, what i call, a QuickAction-popup.
This is not just a Window, this also has a pointer that points to a View of our choice.
This is a bit more complex code, that calculate where to show the pointer/arrow, has animations and more.
It has a bit of documentation, but i would fill this tutorial if i was to explain each part.
If you have any question, please just ask.

Moving on..

A little class
Now we are going to create the holder for the items in the QuickAction-popup, classed ActionItems.
Create a new class and name it ActionItem.
This is our code for that one:
package com.example.mywindow;

import android.graphics.drawable.Drawable;
import android.graphics.Bitmap;

/**
 *  @author Pontus Holmberg (EndLessMind)
 *  Email: the_mr_hb@hotmail.com
 **/
public class ActionItem {
	private Drawable icon;
	private Bitmap thumb;
	private String title;
	private int actionId = -1;
    private boolean selected;
    private boolean sticky;
	
    /**
     * Constructor
     * 
     * @param actionId  Action id for case statements
     * @param title     Title
     * @param icon      Icon to use
     */
    public ActionItem(int actionId, String title, Drawable icon) {
        this.title = title;
        this.icon = icon;
        this.actionId = actionId;
    }
    
    /**
     * Constructor
     */
    public ActionItem() {
        this(-1, null, null);
    }
    
    /**
     * Constructor
     * 
     * @param actionId  Action id of the item
     * @param title     Text to show for the item
     */
    public ActionItem(int actionId, String title) {
        this(actionId, title, null);
    }
    
    /**
     * Constructor
     * 
     * @param icon {@link Drawable} action icon
     */
    public ActionItem(Drawable icon) {
        this(-1, null, icon);
    }
    
    /**
     * Constructor
     * 
     * @param actionId  Action ID of item
     * @param icon      {@link Drawable} action icon
     */
    public ActionItem(int actionId, Drawable icon) {
        this(actionId, null, icon);
    }
	
	/**
	 * Set action title
	 * 
	 * @param title action title
	 */
	public void setTitle(String title) {
		this.title = title;
	}
	
	/**
	 * Get action title
	 * 
	 * @return action title
	 */
	public String getTitle() {
		return this.title;
	}
	
	/**
	 * Set action icon
	 * 
	 * @param icon {@link Drawable} action icon
	 */
	public void setIcon(Drawable icon) {
		this.icon = icon;
	}
	
	/**
	 * Get action icon
	 * @return  {@link Drawable} action icon
	 */
	public Drawable getIcon() {
		return this.icon;
	}
	
	 /**
     * Set action id
     * 
     * @param actionId  Action id for this action
     */
    public void setActionId(int actionId) {
        this.actionId = actionId;
    }
    
    /**
     * @return  Our action id
     */
    public int getActionId() {
        return actionId;
    }
    
    /**
     * Set sticky status of button
     * 
     * @param sticky  true for sticky, pop up sends event but does not disappear
     */
    public void setSticky(boolean sticky) {
        this.sticky = sticky;
    }
    
    /**
     * @return  true if button is sticky, menu stays visible after press
     */
    public boolean isSticky() {
        return sticky;
    }
    
	/**
	 * Set selected flag;
	 * 
	 * @param selected Flag to indicate the item is selected
	 */
	public void setSelected(boolean selected) {
		this.selected = selected;
	}
	
	/**
	 * Check if item is selected
	 * 
	 * @return true or false
	 */
	public boolean isSelected() {
		return this.selected;
	}

	/**
	 * Set thumb
	 * 
	 * @param thumb Thumb image
	 */
	public void setThumb(Bitmap thumb) {
		this.thumb = thumb;
	}
	
	/**
	 * Get thumb image
	 * 
	 * @return Thumb image
	 */
	public Bitmap getThumb() {
		return this.thumb;
	}
}

This code, is well documented, this is because i want to save your time.
But basically, it holds the values that will be shown in the QuickAction-popup.


Animations and styles
This tutorial requires 17(!) animations, so to save time and space, i'll just write their name and then the xml-code.
In you'r res-directory, create a folder called "anim". This is where all the animations are going.

disappear.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">

	<alpha
		android:interpolator="@android:anim/decelerate_interpolator"
		android:fromAlpha="1.0" android:toAlpha="0.0"
		android:duration="400"
	/>
</set>



fadein.xml
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator"
android:fromAlpha="0.0" android:toAlpha="1.0"
android:duration="9000" />



fadeout.xml
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator"
android:fromAlpha="1.0" android:toAlpha="0.0"
android:duration="9000" />



grow_from_bottom.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
	<scale
		android:fromXScale="0.3" android:toXScale="1.0"
		android:fromYScale="0.3" android:toYScale="1.0"
		android:pivotX="50%" android:pivotY="100%"
		android:duration="@android:integer/config_shortAnimTime"
	/>
	<alpha
		android:interpolator="@android:anim/decelerate_interpolator"
		android:fromAlpha="0.0" android:toAlpha="1.0"
		android:duration="@android:integer/config_shortAnimTime"
	/>
</set>




grow_from_bottomleft_to_topright.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
	<scale
		android:fromXScale="0.3" android:toXScale="1.0"
		android:fromYScale="0.3" android:toYScale="1.0"
		android:pivotX="0%" android:pivotY="50%"
		android:duration="@android:integer/config_shortAnimTime"
	/>
	<alpha
		android:interpolator="@android:anim/decelerate_interpolator"
		android:fromAlpha="0.0" android:toAlpha="1.0"
		android:duration="@android:integer/config_shortAnimTime"
	/>
</set>



grow_from_bottomright_to_topleft.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
	<scale
		android:fromXScale="0.3" android:toXScale="1.0"
		android:fromYScale="0.3" android:toYScale="1.0"
		android:pivotX="100%" android:pivotY="50%"
		android:duration="@android:integer/config_shortAnimTime"
	/>
	<alpha
		android:interpolator="@android:anim/decelerate_interpolator"
		android:fromAlpha="0.0" android:toAlpha="1.0"
		android:duration="@android:integer/config_shortAnimTime"
	/>
</set>



grow_from_top.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
	<scale
		android:fromXScale="0.3" android:toXScale="1.0"
		android:fromYScale="0.3" android:toYScale="1.0"
		android:pivotX="50%" android:pivotY="0%"
		android:duration="@android:integer/config_shortAnimTime"
	/>
	<alpha
		android:interpolator="@android:anim/decelerate_interpolator"
		android:fromAlpha="0.0" android:toAlpha="1.0"
		android:duration="@android:integer/config_shortAnimTime"
	/>
</set>




grow_from_topleft_to_bottomright.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
	<scale
		android:fromXScale="0.3" android:toXScale="1.0"
		android:fromYScale="0.3" android:toYScale="1.0"
		android:pivotX="0%" android:pivotY="0%"
		android:duration="@android:integer/config_shortAnimTime"
	/>
	<alpha
		android:interpolator="@android:anim/decelerate_interpolator"
		android:fromAlpha="0.0" android:toAlpha="1.0"
		android:duration="@android:integer/config_shortAnimTime"
	/>
</set>




grow_from_topright_to_bottomleft.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
	<scale
		android:fromXScale="0.3" android:toXScale="1.0"
		android:fromYScale="0.3" android:toYScale="1.0"
		android:pivotX="100%" android:pivotY="0%"
		android:duration="@android:integer/config_shortAnimTime"
	/>
	<alpha
		android:interpolator="@android:anim/decelerate_interpolator"
		android:fromAlpha="0.0" android:toAlpha="1.0"
		android:duration="@android:integer/config_shortAnimTime"
	/>
</set>



pump_bottom.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
	<scale
		android:fromXScale="1.1" android:toXScale="1.0"
		android:fromYScale="1.1" android:toYScale="1.0"
		android:pivotX="50%" android:pivotY="100%"
		android:duration="@android:integer/config_shortAnimTime"
	/>
	<alpha
		android:interpolator="@android:anim/decelerate_interpolator"
		android:fromAlpha="0.0" android:toAlpha="1.0"
		android:duration="@android:integer/config_shortAnimTime"
	/>
</set>




pump_top.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
	<scale
		android:fromXScale="1.1" android:toXScale="1.0"
		android:fromYScale="1.1" android:toYScale="1.0"
		android:pivotX="50%" android:pivotY="0%"
		android:duration="@android:integer/config_shortAnimTime"
	/>
	<alpha
		android:interpolator="@android:anim/decelerate_interpolator"
		android:fromAlpha="0.0" android:toAlpha="1.0"
		android:duration="@android:integer/config_shortAnimTime"
	/>
</set>




shrink_from_bottom.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
	<scale
		android:fromXScale="1.0" android:toXScale="0.3"
		android:fromYScale="1.0" android:toYScale="0.3"
		android:pivotX="50%" android:pivotY="0%"
		android:duration="@android:integer/config_shortAnimTime"
	/>
	<alpha
		android:interpolator="@android:anim/accelerate_interpolator"
		android:fromAlpha="1.0" android:toAlpha="0.0"
		android:duration="@android:integer/config_shortAnimTime"
	/>
</set>




shrink_from_bottomleft_to_topright.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
	<scale
		android:fromXScale="1.0" android:toXScale="0.3"
		android:fromYScale="1.0" android:toYScale="0.3"
		android:pivotX="100%" android:pivotY="0%"
		android:duration="@android:integer/config_shortAnimTime"
	/>
	<alpha
		android:interpolator="@android:anim/accelerate_interpolator"
		android:fromAlpha="1.0" android:toAlpha="0.0"
		android:duration="@android:integer/config_shortAnimTime"
	/>
</set>



shrink_from_bottomright_to_topleft.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
	<scale
		android:fromXScale="1.0" android:toXScale="0.3"
		android:fromYScale="1.0" android:toYScale="0.3"
		android:pivotX="0%" android:pivotY="0%"
		android:duration="@android:integer/config_shortAnimTime"
	/>
	<alpha
		android:interpolator="@android:anim/accelerate_interpolator"
		android:fromAlpha="1.0" android:toAlpha="0.0"
		android:duration="@android:integer/config_shortAnimTime"
	/>
</set>




shrink_from_top.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
	<scale
		android:fromXScale="1.0" android:toXScale="0.3"
		android:fromYScale="1.0" android:toYScale="0.3"
		android:pivotX="50%" android:pivotY="100%"
		android:duration="@android:integer/config_shortAnimTime"
	/>
	<alpha
		android:interpolator="@android:anim/accelerate_interpolator"
		android:fromAlpha="1.0" android:toAlpha="0.0"
		android:duration="@android:integer/config_shortAnimTime"
	/>
</set>




shrink_from_topleft_to_bottomright.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
	<scale
		android:fromXScale="1.0" android:toXScale="0.3"
		android:fromYScale="1.0" android:toYScale="0.3"
		android:pivotX="100%" android:pivotY="100%"
		android:duration="@android:integer/config_shortAnimTime"
	/>
	<alpha
		android:interpolator="@android:anim/accelerate_interpolator"
		android:fromAlpha="1.0" android:toAlpha="0.0"
		android:duration="@android:integer/config_shortAnimTime"
	/>
</set>



shrink_from_topright_to_bottomleft.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
	<scale
		android:fromXScale="1.0" android:toXScale="0.3"
		android:fromYScale="1.0" android:toYScale="0.3"
		android:pivotX="0%" android:pivotY="100%"
		android:duration="@android:integer/config_shortAnimTime"
	/>
	<alpha
		android:interpolator="@android:anim/accelerate_interpolator"
		android:fromAlpha="1.0" android:toAlpha="0.0"
		android:duration="@android:integer/config_shortAnimTime"
	/>
</set>




Now, we need styles as well. There should be a xml-file named styles in res->values
Add the following before </resourses>
    <style name="Animations" />

	<!-- PopDownMenu -->
	<style name="Animations.PopDownMenu" />
	
	<style name="Animations.PopDownMenu.Center">
		<item name="@android:windowEnterAnimation">@anim/grow_from_top</item>
		<item name="@android:windowExitAnimation">@anim/shrink_from_bottom</item>
	</style>
	
	<style name="Animations.PopDownMenu.Left">
		<item name="@android:windowEnterAnimation">@anim/grow_from_topleft_to_bottomright</item>
		<item name="@android:windowExitAnimation">@anim/shrink_from_bottomright_to_topleft</item>
	</style>
	
	<style name="Animations.PopDownMenu.Right">
		<item name="@android:windowEnterAnimation">@anim/grow_from_topright_to_bottomleft</item>
		<item name="@android:windowExitAnimation">@anim/shrink_from_bottomleft_to_topright</item>
	</style>
	
	<style name="Animations.PopDownMenu.Reflect">
		<item name="@android:windowEnterAnimation">@anim/pump_top</item>
		<item name="@android:windowExitAnimation">@anim/disappear</item>
	</style>
	
	<!-- PopUpMenu -->
	<style name="Animations.PopUpMenu" />
	
	<style name="Animations.PopUpMenu.Center">
		<item name="@android:windowEnterAnimation">@anim/grow_from_bottom</item>
		<item name="@android:windowExitAnimation">@anim/shrink_from_top</item>
	</style>
	
	<style name="Animations.PopUpMenu.Left">
		<item name="@android:windowEnterAnimation">@anim/grow_from_bottomleft_to_topright</item>
		<item name="@android:windowExitAnimation">@anim/shrink_from_topright_to_bottomleft</item>
	</style>
	
	<style name="Animations.PopUpMenu.Right">
		<item name="@android:windowEnterAnimation">@anim/grow_from_bottomright_to_topleft</item>
		<item name="@android:windowExitAnimation">@anim/shrink_from_topleft_to_bottomright</item>
	</style>
	
	<style name="Animations.PopUpMenu.Reflect">
		<item name="@android:windowEnterAnimation">@anim/pump_bottom</item>
		<item name="@android:windowExitAnimation">@anim/disappear</item>
	</style>
    




Layouts
Wow, it's a lot if animations. Well, we are not done with the xml yet.
Next up we have the layouts, we have 6 layouts + changes in the activity_main.xml.
For the 6 new layouts, i'm going to do the same as with the animations.

action_item_horizontal.xml
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" 
    android:clickable="true"
    android:focusable="true"
    android:background="@drawable/action_item_btn">
            
    <ImageView
        android:id="@+id/iv_icon"
        android:layout_centerHorizontal="true"
        android:layout_width="24dp" 
        android:layout_height="24dp"/>

    <TextView 
        android:id="@+id/tv_title"
        android:layout_below="@+id/iv_icon"
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:layout_centerHorizontal="true"
        android:gravity="center_horizontal"
        android:paddingLeft="5dip"
        android:paddingRight="5dip"
        		android:layout_marginBottom="5dp"
		android:layout_marginTop="3dp"
        android:text="Chart"
        android:textColor="#fff"/>
                                             
</RelativeLayout>         


action_item_vertical.xml
<LinearLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="horizontal"
	android:layout_width="fill_parent"
	android:layout_height="wrap_content" 
	android:clickable="true"
	android:focusable="true"
	android:background="@drawable/action_item_btn">
        	
	<ImageView
		android:id="@+id/iv_icon" 
		android:layout_width="30dp" 
		android:layout_height="30dp"/>

	<TextView 
		android:id="@+id/tv_title"
		android:layout_width="fill_parent" 
		android:layout_height="fill_parent" 
		android:gravity="center_vertical"
		android:paddingLeft="5dip"
		android:paddingRight="10dip"
		android:layout_marginBottom="5dp"
		android:layout_marginTop="3dp"
		android:text="Chart"
		android:textColor="#fff"/>
									         
</LinearLayout>         


horiz_separator.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="wrap_content"
  android:layout_height="fill_parent">
<TextView android:layout_height="fill_parent"
    android:gravity="center"
    android:layout_width="2px"
    android:text=" "
    android:background="#000000"/>    
</RelativeLayout>



popup_horizontal.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    >
        
    <ScrollView
        android:id="@+id/scroller"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dip"
        android:background="@color/Black"
        android:fadingEdgeLength="5dip"
        android:scrollbars="none" >
        
        <LinearLayout
            android:id="@+id/tracks"
            android:orientation="horizontal"
            android:layout_width="wrap_content"
            android:layout_height="fill_parent"
            android:layout_weight="1"
            android:padding="10dip"/>
       
    </ScrollView >
    
    <ImageView
        android:id="@+id/arrow_up"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/arrow_up" />
        
    <ImageView
        android:id="@+id/arrow_down"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/scroller"
        android:layout_marginTop="-4dip"
        android:src="@drawable/arrow_down" />

</RelativeLayout>


popup_vertical.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 
	xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    >
	    

	<ScrollView
	    android:id="@+id/scroller"
	    android:layout_width="wrap_content"
	    android:layout_height="wrap_content"
	    android:layout_marginTop="16dip"
	    android:background="@color/Black"
	    android:fadingEdgeLength="5dip"
	    android:scrollbars="none" >
        
    	<LinearLayout
	    	android:id="@+id/tracks"
	    	android:orientation="vertical"
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
	        android:layout_weight="1"
	        android:padding="10dip"/>
       
	</ScrollView >
 	
 	<ImageView
        android:id="@+id/arrow_up"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/arrow_up" />
        
 	<ImageView
        android:id="@+id/arrow_down"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
    	android:layout_below="@id/scroller"
      	android:layout_marginTop="-4dip"
        android:src="@drawable/arrow_down" />

</RelativeLayout>


popup.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@color/Black"
    android:gravity="center"
    android:orientation="vertical" >



    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="left"
        android:layout_marginLeft="5dp"
        android:layout_marginTop="10dp"
        android:text="A PopupWindow"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:textColor="@color/light_gray" />

            <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="2dp"
        android:background="#33b5e5"
        android:layout_marginTop="10dp"
        android:layout_marginBottom="10dp"
        android:orientation="vertical" >
    </LinearLayout>

            

    <LinearLayout
        android:id="@+id/linearLayout1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:layout_marginBottom="15dp"
        android:orientation="vertical" >

<TextView
    android:id="@+id/textView2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="This is a popupWindow"
    android:textAppearance="?android:attr/textAppearanceMedium"
    android:textColor="@color/light_gray" />

        <Button
            android:id="@+id/buttonclose"
            android:layout_width="108dp"
            android:layout_height="wrap_content"
            android:text="Close" />

    </LinearLayout>

</LinearLayout>


Now to the activity_main.xml
Right now, it only contains a RelativeLayout but we are going to everything with this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    tools:context=".MainActivity" >

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Open menu" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Open Window" />

</LinearLayout>


That's it for the layouts
Almost done, guys! :)/>


Colors and drawables
So, that last thing we need before we can put everything together, is colors and drawables.
2 colors, 3 images and 1 xml-drawable

Go into res->values and open colors.xml
Add the following before </resources>
<color name="Black">#000000</color>
    <color name="light_gray">#d8d8d8</color>


In your drawable-folder, add a xml-file and name it action_item_btn.xml
Replace all default code with:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
    android:dither="true">

    <item 
    	android:state_window_focused="false"
        android:drawable="@android:color/transparent" />
    <item 
    	android:state_pressed="true"
        android:drawable="@drawable/action_item_selected"/>
    <item 
    	android:state_focused="true"
        android:drawable="@drawable/action_item_selected"/>
    <item
        android:drawable="@android:color/transparent"/>
        
</selector>


Now, download the 3 images below and add them to the drawable-folder

action_item_selected.9.png
Attached Image

arrow_down.png
Attached Image

arrow_up.png
Attached Image

Putting it all together
Wow, that was alot.
Now we only have to put everything together with some last piece of java-code.

Open the MainActivity.java

Replace everything whit this:
package com.example.mywindow;




import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.View.onclickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.PopupWindow;
import android.widget.Toast;

public class MainActivity extends Activity {

	private Button btn1, btn2;
	private QuickAction quick;
	private PopupWindow window;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		btn1 = (Button) findViewById(R.id.button1);
		btn2 = (Button) findViewById(R.id.button2);
		btn1.setonclickListener(btn1_Click);
		btn2.setonclickListener(btn2_Click);
		ActionItem itm1 = new ActionItem(1, "Item1", null);
		ActionItem itm2 = new ActionItem(2, "Item2", null);
		quick = new QuickAction(this, QuickAction.VERTICAL);
		quick.addActionItem(itm1);
		quick.addActionItem(itm2);
		quick.setOnActionItemClickListener(quick_Clicked);
	}

	private onclickListener btn1_Click = new onclickListener() {

		@Override
		public void onclick(View v) {
			quick.show(v);
		}
		
	};
	
	private onclickListener btn2_Click = new onclickListener() {

		@Override
		public void onclick(View v) {
			 LayoutInflater inflater = (LayoutInflater) MainActivity.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
			  View layout = inflater.inflate(R.layout.popup, null);
			  window = new PopupWindow(layout, 300, 300, true);
			  window.showAtLocation(layout,17, 0, 0);
			  Button btn = (Button) layout.findViewById(R.id.buttonclose);
			  btn.setonclickListener(new onclickListener() {

				@Override
				public void onclick(View v) {
					window.dismiss();
				}
				  
			  });
		}
		
		
	};
	
	private QuickAction.OnActionItemClickListener quick_Clicked = new QuickAction.OnActionItemClickListener() {
		
		@Override
		public void onItemClick(QuickAction source, int pos, int actionId) {
			if (actionId == 1) {
				Toast.makeText(MainActivity.this, "Item 1 was clicked", Toast.LENGTH_LONG).show();
			} else if (actionId == 2) {
				Toast.makeText(MainActivity.this, "Item 2 was clicked", Toast.LENGTH_LONG).show();
			}
		}
	};
}



So, what do we have here?
Well, we get the layout and then listeners to the buttons.
Also, we create 2 ActionItems and adds them to the QuickAction.
We also set the OnActionItemClickListener to the QuickAction.

In the btn1_Click, we display the QuickAction.
In the btn2_Click, we create a PopupWindow, with a onclickListener for the close-button, and then shows it.


This is the finished product.
Attached Image Attached Image

Here is the source-code with complied apk
Attached File  com.example.mywindow.zip (1015.28K)
Number of downloads: 2413

Hope this can be helpful, and i hope you the best of luck, making android software.

Cheers, EndLessMind

Is This A Good Question/Topic? 1
  • +

Page 1 of 1