PopupWindow可以在窗口的任意位置显示,相对于其它窗口组件显示的位置更灵活,Popupwindow不会给页面的其它部分添加蒙层(可通过代码自定义添加)
常用属性设置
View popView = LayoutInflater.from(context).inflate(R.layout.dialog_wheel_select, null);
PopupWindow popWindow = new PopupWindow(popView, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
//dismiss时的回调事件
popWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
WindowUtils.setBackgroundAlpha(context, 1.0f);
}
});
//设置popupWindow的显示和隐藏动画
popWindow.setAnimationStyle(R.style.WheelSelect);
//这个函数不止能设置背景,加上它之后setOutsideTouchable()才会生效;而且只有加上它之后,点击手机返回按钮才可以关闭PopupWindow,否则响应的是对应Activity
popWindow.setBackgroundDrawable(new ColorDrawable());
//设置PopupWindow是否响应touch事件,默认是true,如果为false,所有按钮不可点击
popWindow.setTouchable(true);
//是否可获取焦点,设置为true会响应back键的返回,同时拥有setOutsideTouchable(true)的作用.
popWindow.setFocusable(true);
//其它区域添加蒙色背景
WindowUtils.setBackgroundAlpha(context, 0.5f);
//设置显示位置
popWindow.showAtLocation(popView, Gravity.BOTTOM, 0, 0);
WindowUtils通过代码添加蒙层(显示窗口前调用):
private static void applyDim(Activity activity, float bgAlpha) {
if (Build.VERSION.SDK_INT >= 18) {
ViewGroup parent = (ViewGroup) activity.getWindow().getDecorView().getRootView();
Drawable dim = new ColorDrawable(-16777216);
dim.setBounds(0, 0, parent.getWidth(), parent.getHeight());
dim.setAlpha((int) (255.0F * bgAlpha));
ViewGroupOverlay overlay = parent.getOverlay();
overlay.add(dim);
}
}
通过代码清除蒙层(销毁时调用):
private static void clearDim(Activity activity) {
if (Build.VERSION.SDK_INT >= 18) {
ViewGroup parent = (ViewGroup) activity.getWindow().getDecorView().getRootView();
ViewGroupOverlay overlay = parent.getOverlay();
overlay.clear();
}
}
/**
* 设置背景阴影(蒙色)
*
* @param mContext context
* @param bgAlpha 1.0F为清除灰蒙背景,0.5F为添加蒙色
*/
public static void setBackgroundAlpha(Context mContext, float bgAlpha) {
if (bgAlpha == 1.0F) {
clearDim((Activity) mContext);
} else {
applyDim((Activity) mContext, bgAlpha);
}
}
构造方法
PopupWindow ()
PopupWindow (View contentView)
PopupWindow (View contentView, int width, int height)
PopupWindow (View contentView, //PopupWindow的内容View, 相当于setContentView
int width, // 宽, 相当于setwidth()
int height, // 高, 相当于setHeight
boolean focusable) // 是否可获取焦点, 相当于setFocusable()
一般使用第三个和第四个构造函数,创建PopuWindow必须指定宽高,可使用LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT
LinearLayout可替换为对应的布局文件类
调用显示的方式
//1.附着某个控件用showAsDropDown
//2.设置显示位置用showAtLocation
//showAsDropDown
void showAsDropDown (View anchor) // 弹窗显示在某个控件左下方
void showAsDropDown (View anchor, //显示在某个控件左下方
int xoff, //在依附控件为原点的X偏移坐标
int yoff) //在依附控件Y为原点的Y偏移坐标
void showAsDropDown (View anchor,
int xoff,
int yoff,
int gravity) //弹窗显示在控件的左下方还是右下方, 参数有Gravity.RIGHT/Gravity.LEFT. 默认是左下方
//showAsDropDown不存在Gravity.TOP或Gravity.BOTTOM效果
showAtLocation
//parent在某个控件左下方(只要是屏幕上任意控件对象即可)gravity相对于父控件的位置(例如正中央Gravity.CENTER,下方Gravity.BOTTOM等),可以设置偏移或无偏移(0)
showAtLocation(View parent, int gravity, int x, int y):
需要注意的是多次调用show方法, 只会执行第一句
更新状态
//该方法不能更新PopupWindow的宽高, 只能更新参数的状态. 例如更新Focusable和OutsideTouchable
void update ()
更新宽高
void update (int width,int height)
更新显示位置
//该方法相当于重新执行showAsDropDown
void update (View anchor,int width,int height)
void update (View anchor, int xoff,int yoff, int width, int height)
相对位置偏移更新
//相对当前的位置进行偏移,窗口宽高
void update(int x, int y, int width, int height)
//相对偏移,窗口宽高,是否可获取焦点
void update (int x, int y, int width, int height, boolean force)
其它函数
//销毁窗口
public void dismiss()
//是否具有获取焦点的能力,默认为False,一般来讲是没用的,因为普通控件不需要获取焦点,而对于EditText如果不能获取焦点,那么将无法编辑。
public void setFocusable(boolean focusable)
//设置PopupWindow是否响应touch事件,默认是true,如果为false,所有按钮不可点击
public void setTouchable(boolean touchable)
//如果点击PopupWindow以外的区域,PopupWindow是否会消失。
public void setOutsideTouchable(boolean touchable)
//这个函数不止能设置背景,加上它之后setOutsideTouchable()才会生效;而且只有加上它之后,点击手机返回按钮才可以关闭PopupWindow,否则响应的是对应Activity
public void setBackgroundDrawable(Drawable background)
不常用函数
//多点触控
void setSplitTouchEnabled (boolean enabled)
boolean isSplitTouchEnabled ()
//忽略CheekPress事件,当物体触摸在屏幕上的尺寸超过手指尺寸范围, 被判定为CheekPress事件(脸颊点击)//默认为false, 即不忽略
void setIgnoreCheekPress ()
//解决NavigationBar重叠,这是Android5.0(API22)后添加的方法, 默认为true. 为true时将不会与导航栏重叠.
void setAttachedInDecor (boolean enabled)
//遮盖附着View,如果为true对齐方式默认从View anchor的左下角变成了左上角了.
void setOverlapAnchor (boolean overlapAnchor)
boolean getOverlapAnchor ()
//窗口裁剪,PopupWindow默认是不会超出屏幕边界的. 但是如果该方法为false时会采用精准位置, 能超出屏幕范围.
void setClippingEnabled (boolean enabled)
boolean isClippingEnabled ()
//通过样式设置进出动画,传入一个Style的样式id
void setAnimationStyle (int animationStyle)
int getAnimationStyle ()
//style样式的进出动画
<style name="popupwindow_anim_style">
<item name="android:windowEnterAnimation">@anim/dialog_bottom_enter</item>
<item name="android:windowExitAnimation">@anim/dialog_bottom_exit</item>
</style>
//单独设置进入动画
void setEnterTransition (Transition enterTransition)
Transition getEnterTransition ()
//单独设置退出动画
void setExitTransition (Transition exitTransition)
Transition getExitTransition ()
//获取最大高度
int getMaxAvailableHeight (View anchor)
//控件Y轴偏移后可显示的最大高度
int getMaxAvailableHeight (View anchor,int yOffset)
//api24增加的方法, 由于我手上没有7.0设备就不说了.
int getMaxAvailableHeight (View anchor, int yOffset, boolean ignoreBottomDecorations)
输入模式
//支持三种模式(一般用不到)
PopupWindow.INPUT_METHOD_FROM_FOCUSABLE 根据可否获取焦点判断是否可输入
PopupWindow.INPUT_METHOD_NEEDED 允许输入
PopupWindow.INPUT_METHOD_NOT_NEEDED 不允许输入
void setInputMethodMode (int mode)
int getInputMethodMode ()
软键盘模式
//九种取值, 可组合使用,分为两类:
//显示模式
PopupWindow.SOFT_INPUT_STATE_UNSPECIFIED 默认模式
PopupWindow.SOFT_INPUT_STATE_HIDDEN
PopupWindow.SOFT_INPUT_STATE_ALWAYS_HIDDEN 总是隐藏
PopupWindow.SOFT_INPUT_STATE_UNCHANGED
PopupWindow.SOFT_INPUT_STATE_VISIBLE
PopupWindow.SOFT_INPUT_STATE_ALWAYS_VISIBLE 自动弹出软键盘
//调整模式
PopupWindow.SOFT_INPUT_ADJUST_UNSPECIFIED 默认模式
PopupWindow.SOFT_INPUT_ADJUST_RESIZE 软键盘弹出后PopupWindow会自动调整坐标,不被遮挡
PopupWindow.SOFT_INPUT_ADJUST_PAN
//组合时赋值WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE
void setSoftInputMode (int mode)
int getSoftInputMode ()
事件监听
//dismiss监听
void setOnDismissListener (PopupWindow.OnDismissListener onDismissListener)
//触摸事件拦截
void setTouchInterceptor (View.OnTouchListener l)
一.编写popupwindow的动画的xml文件
1、从底部退出动画pop_exit_anim.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="420"
android:fromYDelta="0"
android:toYDelta="100%" />
</set>
2、从底部显示动画pop_enter_anim.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="420"
android:fromYDelta="100%"
android:toYDelta="0" />
</set>
二.编写popupwindow动画的style,在styles.xml文件中设置一个动画样式
<style name="popwin_anim_style" parent="android:Animation">
<item name="android:windowEnterAnimation">@anim/pop_enter_anim</item>
<item name="android:windowExitAnimation">@anim/pop_exit_anim</item>
</style>
三.在程序中为PopupWindow设置动画效果。
PopupWindow pop = new PopupWindow(view, ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
pop.setAnimationStyle(R.style.popwin_anim_style);
PopupWindow必须设置View contentView,int width, int height,少任意一个就不能弹出来PopupWindow。
所以如果用Context构造函数来初始化,完整的代码应该是这样的:
View contentView = LayoutInflater.from(MainActivity.this).inflate(R.layout.popuplayout, null);
PopupWindwo popWnd = PopupWindow (context);
popWnd.setContentView(contentView);
popWnd.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
popWnd.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
为什么要强制设置PopupWindow的Height、Width
布局的大小,应该是在它父布局的基础上决定的。父布局显示大小确定了以后,才能确定子布局文件的大小。
所以我们设置的宽高,就是给布局文件的父布局设置宽高。