PopupWindow的基本使用一

PopupWindow在开发中也是很常见的一个控件,由于多数情况下PopupWindow都是弹出一个列表框,从Android3.0开始官方提供了两个专门用于弹出列表的弹框ListPopupWindow和PopupMenu,如果想要支持更低的版本可以使用support v7中相应的类。

创建PopupWindow

创建PopupWindow有两种类型的构造方法,一种是传统方式创建View的方式,另外一种是直接传进一个View的构造方式。

//方式一
PopupWindow(Context context)
PopupWindow(Context context, AttributeSet attrs)
PopupWindow(Context context, AttributeSet attrs, int defStyleAttr)
PopupWindow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
//方式二
PopupWindow(View contentView)
PopupWindow(int width, int height)
PopupWindow(View contentView, int width, int height)
PopupWindow(View contentView, int width, int height, boolean focusable)

PopupWindow更类似与一个工具类,在工具类中存入一个View,在操作的时候弹出或销毁该View。查看源码我们也可以看出来PopupWindow并没有继承自View,因此在使用的时候与View还是有很显著差别的,View可以定义子在布局文件中,但是没有哪个开发者将PopupWindow放在布局文件中。在传入上下文Context的时候跟创建View类似,如果创建一个View需要传入一个Context实例,方式一不用多说了,在方式二中只要传入一个View同样可以通过View中getContext方法获取一个Context实例。

在创建一个PopupWindow的时候有三个最基本的属性必须设置,contentView、width和height,这里具体的为什么后面再做分析,虽然已经传入了View,但是View的高度是由父控件决定的,在创建的时候是不知道它的父控件是谁的,因此宽高都是未知的,如果不设置是显示不出来PopupWindow的。

View view=View.inflate(context, R.layout.layout_popup,null);
popupWindow.setWidth(width);
popupWindow.setHeight(height);
popupWindow.setContentView(view);

这里用了三行代码才设置完毕所必须的属性,事实上使用方式二中的第3个和第4个构造方法可以直接构造出需要显示的PopupWindow,focusable这个属性不是必须的,但是在交互的时候缺少该属性也会引发很奇葩的问题,在后面也会介绍。

设置PopupWindow显示位置

设置PopupWindow显示位置主要有两种类型showAsDropDown和showAtLocation:

showAsDropDown(View anchor)
showAsDropDown(View anchor, int xoff, int yoff)
showAsDropDown(View anchor, int xoff, int yoff, int gravity)//API 19新增
showAtLocation (View parent, int gravity, int x, int y)
showAsDropDown(View anchor, int xoff, int yoff, int gravity)

该方法是设置相对于anchor的位置,如果showAsDropDown只有一个参数,就是相对于anchor左下方,xoff和yoff是相对anchor左下方为基点在x方向移动xoff像素,在y方向移动yoff像素,gravity与showAtLocation中gravity属性是有本质区别的,该方法的gravity是相对于anchor方位。

showAtLocation (View parent, int gravity, int x, int y)

该方法是相对于屏幕位置,位置展示跟parent基本没有关系,parent只是为了获取一个WindowToken,用于检索出该View所处的Window窗体,然后设置PopupWindow的布局参数到WindowManager.LayoutParams上面。

public void showAtLocation(View parent, int gravity, int x, int y) {
	showAtLocation(parent.getWindowToken(), gravity, x, y);
}
public void showAtLocation(IBinder token, int gravity, int x, int y) {
	//...
	final WindowManager.LayoutParams p = createPopupLayoutParams(token);
	preparePopup(p);

	// Only override the default if some gravity was specified.
	if (gravity != Gravity.NO_GRAVITY) {
		p.gravity = gravity;
	}

	p.x = x;
	p.y = y;

	invokePopup(p);
}

//下面方法来自View中方法
/**
 * Retrieve a unique token identifying the window this view is attached to.
 * @return Return the window's token for use in
 * {@link WindowManager.LayoutParams#token WindowManager.LayoutParams.token}.
 */
public IBinder getWindowToken() {
	return mAttachInfo != null ? mAttachInfo.mWindowToken : null;
}

其它常用方法

dismiss ()
setAnimationStyle(int animationStyle)
setOutsideTouchable(boolean touchable)
setBackgroundDrawable(Drawable background)
setFocusable(boolean focusable)

比较常用的方法也就这么多了,接下来介绍Popup简单使用。

PopupWindow简单使用

本文实例只是为了演示PopupWindow基本使用,布局都是使用较简单的方式呈现。

showAsDropDown(View anchor)

先看一下布局文件,非常简单内部仅有一个View设置一个背景色。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <View android:layout_height="match_parent"
        android:background="#ff4081"
        android:layout_width="match_parent"/>
</LinearLayout>

下面创建一个PopupWindow,这里使用两种创建方式,究竟使用哪一种方式看个人习惯而定。

View view=View.inflate(this,R.layout.layout_popup,null);

//方式一
popupWindow=new PopupWindow(this);
popupWindow.setContentView(view);
popupWindow.setWidth(400);
popupWindow.setHeight(200);
popupWindow.setFocusable(true);

//方式二
popupWindow=new PopupWindow(view, 400, 200, true);

popupWindow.setBackgroundDrawable(new ColorDrawable(Color.parseColor("#00000000")));
popupWindow.showAsDropDown(btn);

showAsDropDown(View anchor, int xoff, int yoff)

showAsDropDown(View anchor)已经显示在了左下方,其实该方法中X方向位移xoff和Y方向位移yoff都是0,PopupWindow中实现源代码如下:

/**
 * Display the content view in a popup window anchored to the bottom-left
 * corner of the anchor view. If there is not enough room on screen to show
 * the popup in its entirety, this method tries to find a parent scroll
 * view to scroll. If no parent scroll view can be scrolled, the
 * bottom-left corner of the popup is pinned at the top left corner of the
 * anchor view.
 *
 * @param anchor the view on which to pin the popup window
 *
 * @see #dismiss()
 */
public void showAsDropDown(View anchor) {
	showAsDropDown(anchor, 0, 0);
}

想要距离anchor View在X方向和Y方向平移,只需要将xoff和yoff传入具体的数值即可。

showAtLocation (View parent, int gravity, int x, int y)

该方法是设置PopupWindow相对于窗口位置,通过gravity参数设置。有部分开发者使用PopupWindow来设计弹出框或者仿写类似QQ弹出菜单都是借助于该方法,然后使用setAnimationStyle设置炫酷的动画。例如从窗口下侧显示使用Gravity.BOTTOM或者显示在屏幕中央使用Gravity.CENTER。

setAnimationStyle(int animationStyle)

PopupWindow设置动画跟设置普通View的动画不同,PopupWindow直译弹出窗体,所以使用动画使用是转场动画windowAnimation,进入动画android:windowEnterAnimation和退出动画android:windowExitAnimation。

设置底部进入动画

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="200"
        android:fromYDelta="100%"
        android:toYDelta="0%"/>
</set>

设置底部退出动画

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="200"
        android:fromYDelta="0%"
        android:toYDelta="100%"/>
</set>

然后在style.xml文件中设置转场动画

<style name="CustomPopAnim">
	<item name="android:windowEnterAnimation">@anim/slide_from_bottom</item>
	<item name="android:windowExitAnimation">@anim/slide_to_bottom</item>
</style>

PopupWindow隐藏

PopupWindow隐藏调用的是dismiss方法,如果想在PopupWindow隐藏的时候处理其它事件可以设置事件监听器。

popupWindow.setOnDismissListener(new OnDismissListener() {
	@Override
	public void onDismiss() {
		//TODO
	}
});

小结

这篇文章先完成到这里,有关其它几个常用的方法在随后的文章继续,同样ListPopupWindow和PopupMenu以及与Dialog的区别也在下一篇文章介绍。

评论

您确定要删除吗?删除之后不可恢复