PopupWindow 弹出对话框的一种,和
AlertDialog类似,可以用来
实现一个悬浮的菜单
API定义:A popup window that can be used to display an arbitrary view. The popup
window is a floating container that appears on top of the current
activity.
AlertDialog和Popupwindow的区别:
1)Popupwindow可以全屏,而且可以控制显示在屏幕的位置,这些都是AlertDialog无法做到的。
2)AlertDialog是非阻塞线程的,Popupwindow是阻塞线程的。
关于Popupwindow阻塞线程,写这篇文章之前,我参考了很多朋友的日志,再和自己的程序运行结果对比,发现差异挺大,以下就把自己的结论贴出来,欢迎大家指出错误。
这个是我的界面,每个按钮分别对应不同的弹出对话框,
- /**
- * 显示AlertDialog对话框:
- *
- * @see AlertDialog是非阻塞式对话框,可以再oncreate方法中直接调用显示
- * :AlertDialog弹出时,点击对话框之外背景,对话框消失,程序不仅响应AlertDialog的操作
- * ,还响应其他操作
- */
- private void showDialog() {
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setTitle("标题");
- builder.setMessage("AlertDialog对话显示的内容");
- // 注意,Dialog内容可以用自定义布局填充
- // builder.setView(view);
- builder.setPositiveButton("确定", new Dialog.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- // TODO
- }
- }).setNegativeButton("取消", new Dialog.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- }
- });
- // 创建对话框
- AlertDialog dialog = builder.create();
- dialog.show();
- }
- /**
- * 显示PopupWiodow对话框
- *
- * @see PopupWindow是阻塞式对话框,PopupWindow弹出时
- * ,背景没有什么变化,但是当我们点击背景的时候,PopupWindow不会消失,但是PopupWindow对话框之外的按钮依然可以点击。
- * Popupwindow可以全屏,而且可以控制显示在屏幕的位置,这些都是AlertDialog无法做到的。
- */
- private void showPopupWindow() {
- LayoutInflater inflater = LayoutInflater.from(context);
- // 加载指定布局作为PopupWindow的显示内容
- View contentView = inflater.inflate(R.layout.item_popup, null);
- popupWindow = new PopupWindow(contentView, LayoutParams.MATCH_PARENT,
- LayoutParams.WRAP_CONTENT);
- // setPopFoucus();
- popupWindow.showAtLocation(btnDialog, Gravity.BOTTOM, 0, 0);
- popupWindow.showAsDropDown(btnDialog);
- }
甚至在弹出PopupWindow的基础上依然可以点击第一个按钮,依然获得响应可以弹出AlertDialog
关于线程阻塞,在oncrete方法中调用直接调用显示PopupWindow时会报出异常
java.lang.RuntimeException: Unable to start activity
Android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?
由于 PopupWindow是依附于Activity之上,当Activity还未创建完成,所以显示PopupWindow时就发生异常
所以 PopupWindow必须在某个事件中显示或者是开启一个新线程去调用,不能直接在onCreate方法中显示
AlertDialog弹出时,点击对话框之外背景,对话框消失,而默认的PopupWindow却没有效果,所以需要加上以下几行代码
- // 设置popupWindow获得焦点
- popupWindow.setTouchable(true);
- // 设置popupWindow以外的区域可点击,点击后空白处,对话框消失
- popupWindow.setOutsideTouchable(true);
- popupWindow.setBackgroundDrawable(new BitmapDrawable(getResources(),
- (Bitmap) null));
PopupWindow的显示及位置设置
window.showAtLocation(parent, Gravity.RIGHT | Gravity.BOTTOM, 10,10);
第一个参数指定PopupWindow的锚点view,即依附在哪个view上。
第二个参数指定起始点为parent的右下角,第三个参数设置以parent的右下角为原点,向左、上各偏移10像素。
第二个参数指定起始点为parent的右下角,第三个参数设置以parent的右下角为原点,向左、上各偏移10像素。
//将PopupWindow作为anchor的下拉窗口显示。即在anchor的左下角显示
window.showAsDropDown(anchor);
//xoff,yoff基于anchor的左下角进行偏移。
window.showAsDropDown(anchor, xoff, yoff);
window.showAsDropDown(anchor);
//xoff,yoff基于anchor的左下角进行偏移。
window.showAsDropDown(anchor, xoff, yoff);
全屏的PopupWindow
- /**
- * 弹出全屏对话框
- */
- private void showPopupFullWindow() {
- // 获得LayoutInflater的另外一种方式
- LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- // 加载指定布局作为PopupWindow的显示内容
- View contentView = inflater.inflate(R.layout.item_popup, null);
- // 注意:popup的全屏是不包括顶部状态栏高度,所以 popup的真正高度是屏幕高度减去状态栏高度,否则会部分显示在外
- int mScreenWidth = getWindowManager().getDefaultDisplay().getWidth();
- int mScreenHeight = getWindowManager().getDefaultDisplay().getHeight();
- Rect rect = new Rect();
- this.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
- int statusBarHeight = rect.top; // 状态栏高度
- int realHeight = mScreenHeight - statusBarHeight;
- // 初始化popupWindow,指定显示内容和宽高
- popupWindow = new PopupWindow(contentView, mScreenWidth, realHeight);
- setPopFoucus();
- popupWindow.showAtLocation(btnDialog, Gravity.BOTTOM, 0, 0);
- popupWindow.showAsDropDown(btnDialog);
- }