目的
平时在接触PoupoWidow时遇到的问题比较多,写这篇文章主要是将自己所了解的一些细节记录下来,避免以后忘记;
该文章主要介绍PopupWindow的参数详情、针对不同场景而产生的不同使用方法;下面PopupWindow用简称pw表示
具体实现
下面的实例没有进行具体需求的分拣哦!不能直接复制,不过直接复制过去pw是能正常显示的,只是会出现些许小问题,因为部分参数出现了冲突,请仔细下面的分析在设置具体的参数哦!
private PopupWindow mPopupWindow;
View view = LayoutInflater.from(mContext).inflate(R.layout.layout_popupwindow, null);
*//创建PopupWindow实例*
mPopupWindow = new PopupWindow(view,LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT,true);
*//设置动画效果*
mPopupWindow.setAnimationStyle(R.style.shop_popup_window_anim);
*//设置遮盖层,需要在dismiss弹框后还原,即1.0f ,设置范围0~1f*
backgroundAlpha(0.7f);
mPopupWindow.setFocusable(true);
mPopupWindow.setBackgroundDrawable(new BitmapDrawable(mContext.getResources(), (Bitmap) null));
mPopupWindow.setOutsideTouchable(false);
mPopupWindow.setTouchInterceptor(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (!mPopupWindow.isOutsideTouchable()){
*//当setOutsideTouchable设置为false时,拦截点击事件*
View mView = mPopupWindow.getContentView();
if (mView!= null){
mView.dispatchTouchEvent(motionEvent);
}
}
return mPopupWindow.isFocusable() && !mPopupWindow.isOutsideTouchable();
}
});
mPopupWindow.getContentView().setFocusableInTouchMode(true);
mPopupWindow.getContentView().setFocusableInTouchMode(true);
mPopupWindow.getContentView().setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View view, int i, KeyEvent keyEvent) {
Log.e(Const.TAG, "onKey: "+i );
return false;
}
});
*//键盘输入的方式*
*//软键盘 SOFT_INPUT_ADJUST_RESIZE 软键盘弹出后PopupWindow会自动调整左边,不被遮挡,INPUT_METHOD_NEEDED 允许输入*
mPopupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
mPopupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
View rootView = LayoutInflater.from(mContext).inflate(R.layout.main,null);
mPopupWindow.showAtLocation(rootView,Gravity.CENTER,0,0);
mPopupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
Log.e(Const.TAG, "onDismiss: " );
*//点击pw以外地方的监听,包括虚拟按键back键*
dismiss();
}
});
参数分析
pw的样式多种多样,不同场景的布局也有差异即参数设置不尽相同,根据具体需求进行自定义
1.alpha pw背景遮盖层的设置,模糊程度
private void backgroundAlpha(float alpha) {
WindowManager.LayoutParams lp = mContext.getWindow().getAttributes();
lp.alpha = alpha;
mContext.getWindow().setAttributes(lp);
}
alpha 取值范围 0 ~ 1 f;值越小模糊程度越高,1f为还原状态;所以当设置了alpha后,dismiss pw后应当还原
2.setAnimationStyle(int animationStyle) 设置动画效果,下面介绍一种比较简单的,根据需求可自行定制
styles.xml 中定义
R.style.shop_popup_window_anim
<style name="shop_popup_window_anim" parent="android:Animation">
<item name="android:windowEnterAnimation">@anim/pop_enter_anim</item>
<item name="android:windowExitAnimation">@anim/pop_exit_anim</item>
</style>
res目录下新建资源文件夹 anim
动画布局xml文件
pop_enter_anim
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="200"
android:fromYDelta="100%p"
android:toYDelta="0" />
<alpha
android:duration="200"
android:fromAlpha="0.0"
android:toAlpha="1.0" />
</set>
pop_exit_anim
<?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="50%p" />
<alpha
android:duration="200"
android:fromAlpha="1.0"
android:toAlpha="0.0" />
</set>
3. setFocusable(boolean focusable) 设置pw焦点
focusable=true时,可以获取焦点,而且点击pw外区域或者back虚拟按键都可dismiss pw
focusable=false 时,无法获取焦点,同理无论pw以外区域还是点击虚拟back键都无法dismiss pw
比如当pw 布局中存在EditText,参数设为false时,输入框无法获取焦点
问题:如果想要pw能获取到焦点,同时点击pw外区域又不想dismiss pw,可参看下面方法
4.setOutsideTouchable(boolean touchable)
目前setOutsideTouchable 不管是true还是false 设置后,点击pw外的区域和点击back键都可以dismiss pw,所以如果想要实现点击pw以外区域无法dismiss pw,则需要将目前setOutsideTouchable设置为false的同时也要将 setFocusable 设置为false,就比较尴尬;
不过可以通过重写setOnTouchListener()监听来拦截点击事件的方法来让点击失效
mPopupWindow.setTouchInterceptor(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (!mPopupWindow.isOutsideTouchable()){
*//当setOutsideTouchable设置为false时,拦截点击事件*
View mView = mPopupWindow.getContentView();
if (mView!= null){
mView.dispatchTouchEvent(motionEvent);
}
}
return mPopupWindow.isFocusable() && !mPopupWindow.isOutsideTouchable();
}
});
这样就可以解决第三点中的问题了
4. setOnKeyListener(View.OnKeyListener l) 监听物理按键回调
如果仅仅只设置这个方法,是不能监听物理按键的,也就是说pw弹出时不会触发
解决办法:需要在popupWindow的主View上设置一个参数
mPopupWindow.getContentView().setFocusableInTouchMode(true);
这样pw弹出时就可以监听物理按键了
mPopupWindow.getContentView().setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View view, int i, KeyEvent keyEvent) {
Log.e(Const.TAG, "onKey: "+i );
return false;
}
});
目前还存在一个虚拟按键的监听问题,比如虚拟按键Back键,暂时没办法进行监听,尝试了很多方法都没有成功;
在setFocusable 设置为true时,点击虚拟back键时,pw是会被dismiss的,后续如果找到办法将会补充
5. 键盘输入模式
mPopupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
mPopupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
PopupWindow.INPUT_METHOD_NEEDED:允许输入
WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE:软键盘弹出后pw会自动调整位置,不被遮挡
其他模式请查看官方文档
6、设置popupWindow位置并显示
方法一:showAsDropDown(View anchor, int xoff, int yoff, int gravity) 附着某个控件(anchor)
mPopupWindow.showAsDropDown(findViewById(R.id.***),-100,100,0);
该方法通过某个具体控件(anchor)来确定位置,以控件anchor为原点,xoff和yoff进行偏移,不管偏移量是多少,pw不会跑出屏幕
anchor: 控件实例化后的对象,且该控件必须显示在屏幕上,不能消失
gravity: 经测试没啥作用
xoff: 向X轴方向的偏移量
yoff: 向Y轴方向的偏移量
方法二:showAtLocation(View parent, int gravity, int xoff, int yoff) 设置屏幕坐标位置
mPopupWindow.showAtLocation(/*rootView*/parent,Gravity.CENTER,0,0);
该方法可设置pw显示在屏幕的具体位置,同理可通过xoff和yoff进行偏移,不管偏移量是多少,pw不会跑出屏幕;
parent: 这个View只要能获取的屏幕的标识即可,控件是什么都没有影响,可以使用方法一中的控件anchor,也可以自定义一个控件 rootView,只要将该rooView加入到屏幕中即可,对PW的位置没有影响
View rootView = LayoutInflater.from(mContext).inflate(R.layout.main,null);
其中布局 R.layout.main 没有要求,随便搞个xml布局即可
另外如果pw的布局宽或者高的大小撑满了整个屏幕,参数设置可能不起作用,因为pw不会跑出屏幕
gravity: 就是于 LinearLayout 中的gravity属性,可设置pw的大概方位,如Top,left,right,bottom等
xoff: 向X轴方向的偏移量
yoff: 向Y轴方向的偏移量
7. setOnDismissListener(PopupWindow.OnDismissListener onDismissListener) 方法
mPopupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
Log.e(Const.TAG, "onDismiss: " );
//点击弹出框以外地方的监听,包括虚拟按键back键
dismiss();
}
});
该方法在pw dismiss消失时触发,所以一些清除操作可放在这进行,比如遮盖层的还原
public void dismiss() {
if (mPopupWindow != null) {
backgroundAlpha(1.0f);
mPopupWindow.dismiss();
mPopupWindow = null;
}
}
好了,目前关于PopupWidow的整理就这些,其他后续再补充…