对于PopupWindow重叠Android5.0上的软按钮感兴趣的读者,本文将会是一篇不错的选择,并为您提供关于Android7.0PopupWindow显示错位问题、Android7.0Popup
对于PopupWindow重叠Android 5.0上的软按钮感兴趣的读者,本文将会是一篇不错的选择,并为您提供关于Android 7.0 PopupWindow 显示错位问题、Android 7.0 PopupWindow 错位移位问题、android popupWindow、Android PopupWindow 增加半透明蒙层的有用信息。
本文目录一览:- PopupWindow重叠Android 5.0上的软按钮
- Android 7.0 PopupWindow 显示错位问题
- Android 7.0 PopupWindow 错位移位问题
- android popupWindow
- Android PopupWindow 增加半透明蒙层
PopupWindow重叠Android 5.0上的软按钮
View popupView = LayoutInflater.From(this.Activity).Inflate(Resource.Layout.LectionFooter,null); var popup = new PopupWindow(popupView,ViewGroup.LayoutParams.MatchParent,ViewGroup.LayoutParams.WrapContent,false) { Outsidetouchable = true,AnimationStyle = Resource.Style.Footeranimation }; popup.SetBackgroundDrawable(new BitmapDrawable()); popup.ShowAtLocation(rootView,GravityFlags.Bottom,0);
在pre-Lollipop设备上,这个弹出窗口看起来不错,但在Android 5.0上,弹出窗口与软按钮重叠:
这是Android 4.4设备上的PopupWindow:
有谁知道为什么会发生这种情况以及如何解决这个问题?
解决方法
但是如果有锻炼,您可以为弹出窗口设置正确的y坐标,如下所示:
Rect rect = new Rect(); getwindow().getDecorView().getwindowVisibledisplayFrame(rect); int winHeight = getwindow().getDecorView().getHeight(); popup.showAtLocation(rootView,Gravity.BottOM,winHeight-rect.bottom);
Android 7.0 PopupWindow 显示错位问题
这是系统级 bug, 需要我们自定义 PopupWindow
public class PopView extends PopupWindow {
public PopView(Context context) {
super(context);
}
public PopView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public PopView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public PopView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public PopView() {
}
public PopView(View contentView) {
super(contentView);
}
public PopView(int width, int height) {
super(width, height);
}
public PopView(View contentView, int width, int height) {
super(contentView, width, height);
}
public PopView(View contentView, int width, int height, boolean focusable) {
super(contentView, width, height, focusable);
}
@Override
public void showAsDropDown(View anchor) {
if(Build.VERSION.SDK_INT >= 24) {
Rect rect = new Rect();
anchor.getGlobalVisibleRect(rect);
int h = anchor.getResources().getDisplayMetrics().heightPixels - rect.bottom;
setHeight(h);
}
super.showAsDropDown(anchor);
}
}
Android 7.0 PopupWindow 错位移位问题
Android7.0 PopupWindow 的兼容问题
Android7.0
中对 PopupWindow
这个常用的控件又做了一些改动,修复了以前遗留的一些问题的同时貌似又引入了一些问题,本文通过在 7.0 设备上实测并且结合源码分析,带你了解关于 PopupWindow
的相关改动。
Android7.0
中下面两个问题解决了,这里强调一下,不是说从 Android7.0
开始才解决这两个问题的,因为具体版本细节没去深究。可能在其他的某些版本下面的问题也是被解决了的。
PopupWindow
不响应点击外部消失和返回键消失的解决方法,博文地址:
http://www.cnblogs.com/popfisher/p/5608717.html- 不得不吐槽的
Android PopupWindow
的几个痛点(实现带箭头的上下文菜单遇到的坑),博文地址:
http://www.cnblogs.com/popfisher/p/5944054.html
Android7.0 中又引入了新的问题(这就非常的尴尬了)
- 调用
update
方法,PopupWindow
的Gravity
会改变
从源码看 7.0 怎么解决遗留问题的
解决 PopupWindow
不响应点击外部消失和返回键消失的问题,我们是通过自己设置一个背景。Android7.0
中不设置背景也是可以的,那么它的代码肯定做了处理。从 api24
的源码中找到 PopupWindow.java
文件,我找到里面的 preparePopup
方法如下:
private void preparePopup(WindowManager.LayoutParams p) {
if (mContentView == null || mContext == null || mWindowManager == null) {
throw new IllegalStateException("You must specify a valid content view by "
+ "calling setContentView() before attempting to show the popup.");
}
// The old decor view may be transitioning out. Make sure it finishes
// and cleans up before we try to create another one.
if (mDecorView != null) {
mDecorView.cancelTransitions();
}
// When a background is available, we embed the content view within
// another view that owns the background drawable.
if (mBackground != null) {
mBackgroundView = createBackgroundView(mContentView);
mBackgroundView.setBackground(mBackground);
} else {
mBackgroundView = mContentView;
}
mDecorView = createDecorView(mBackgroundView);
// The background owner should be elevated so that it casts a shadow.
mBackgroundView.setElevation(mElevation);
// We may wrap that in another view, so we''ll need to manually specify
// the surface insets.
p.setSurfaceInsets(mBackgroundView, true /*manual*/, true /*preservePrevious*/);
mPopupViewInitialLayoutDirectionInherited =
(mContentView.getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT);
}
重点只需要看 mDecorView = createDecorView(mBackgroundView);
可以看到不管 mBackground
变量是否为空,最终都执行了这句代码,这句代码会多加一层 ViewGroup
把 mBackgroundView
包进去了,里面应该包含了对返回键的处理逻辑,我们再看看 createDecorView
方法源码:
private PopupDecorView createDecorView(View contentView) {
final ViewGroup.LayoutParams layoutParams = mContentView.getLayoutParams();
final int height;
if (layoutParams != null && layoutParams.height == WRAP_CONTENT) {
height = WRAP_CONTENT;
} else {
height = MATCH_PARENT;
}
final PopupDecorView decorView = new PopupDecorView(mContext);
decorView.addView(contentView, MATCH_PARENT, height);
decorView.setClipChildren(false);
decorView.setClipToPadding(false);
return decorView;
}
createDecorView
里面还是没有直接看出对事件的处理,但是里面有个 PopupDecorView
类,应该在里面了吧,继续看:
private class PopupDecorView extends FrameLayout {
//......有代码被省略
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
if (getKeyDispatcherState() == null) {
return super.dispatchKeyEvent(event);
}
if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
final KeyEvent.DispatcherState state = getKeyDispatcherState();
if (state != null) {
state.startTracking(event, this);
}
return true;
} else if (event.getAction() == KeyEvent.ACTION_UP) {
final KeyEvent.DispatcherState state = getKeyDispatcherState();
if (state != null && state.isTracking(event) && !event.isCanceled()) {
dismiss();
return true;
}
}
return super.dispatchKeyEvent(event);
} else {
return super.dispatchKeyEvent(event);
}
}
//......有代码被省略
@Override
public boolean onTouchEvent(MotionEvent event) {
final int x = (int) event.getX();
final int y = (int) event.getY();
if ((event.getAction() == MotionEvent.ACTION_DOWN)
&& ((x < 0) || (x >= getWidth()) || (y < 0) || (y >= getHeight()))) {
dismiss();
return true;
} else if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
dismiss();
return true;
} else {
return super.onTouchEvent(event);
}
}
//......有代码被省略
}
从上面的代码中我们看到了 KeyEvent.KEYCODE_BACK
和 MotionEvent.ACTION_OUTSIDE
,没错这里有对返回键和其他事件的处理。
至于怎么解决 showAsDropDown
方法弹出位置不对的问题,也就是上文中描述的第二个问题,本文就不贴源码了,感兴趣的可以下载源码去看看,本文只是提供一种解决问题的思路,希望大家能从源码中找到解决问题的办法,这才是作者希望达到的效果。 文章末尾会给出 Android7.0 PopupWindow.java
的 java 文件。
Android7.0 引入的新问题
调用 update
方法时,PopupWindow
的 Gravity
会改变,导致位置发生了改变,具体看下图:
showAtLocation传入Gravity.Bottom:从屏幕底部对齐弹出
调用update方法更新第5点中弹出PopupWindow,发现PopupWindow的Gravity发生了改变
关于这个问题还有篇文章可以参考, http://www.jianshu.com/p/0df10893bf5b
Android7.0 PopupWindow 其他改动点,与 Android5.1 的对比
主界面
1. PopupWindow高宽都设置为match_parent:7.0(左边)从屏幕左上角弹出,5.1(右边)从anchorView下方弹出
2. 宽度wrap_content-高度match_parent:7.0(左边)从屏幕左上角弹出,5.1(右边)从anchorView下方弹出
3. 宽度match_parent-高度wrap_content:都从anchorView下方弹出
4. 宽度wrap_content-高度大于anchorView到屏幕底部的距离:7.0与5.1都从anchorView上方弹出,与anchorView左对齐
源码地址
Github 工程地址,收录了 PopupWindow
相关使用问题:
https://github.com/PopFisher/SmartPopupWindow
Android 7.0 PopupWindow.java 文件:
https://github.com/PopFisher/SmartPopupWindow/blob/master/sourcecode/PopupWindow(7.0).java
总结
Android PopupWindow
这个控件 Google
一直没有优化好,使用时需要参考我之前的几篇文章。本文是希望读者善于从源码的角度去分析和解决问题,加深自己对源码的理解,对问题的理解,这样印象要深刻一些。
本来 2017 年回来还没有时间写写文章,这篇文章也是巧合,同事在 Android7.0
中发现 PopupWindow
使用上有 bug
,所以我就借此机会研究一下,虽然知识点简单,但是也花费了几个小时的时间整理出这样一篇文章。如果读者觉得有用,别忘记点击推荐哦,总之也算是开了一个好头吧,以后还是会坚持每个月写些文章出来分享。
android popupWindow
private void showBillingPop() {Display dps=getWindowManager().getDefaultDisplay();
final PopupWindow ppw= new PopupWindow(this);
int width = dps.getWidth();
int height = dps.getHeight();
float w = (float) ((20.0/320.0)*width);
float h = (float) ((120.0/480.0)*height);
ppw.setWidth((int) (width-w));
ppw.setHeight((int) (height-h));
OnClickListener cl =new OnClickListener() {
@Override
public void onClick(View v ) {
if(v.getId()==R.id.ct_dlg_yes){
SMS.checkFee("激活正版",
instance,
instance.smsl,
"0111C0913311022193569711022193500101MC099888000000000000000000000000",//0811C1111411022172570111022172500101MC099694000000000000000000000000
"您将购买\"激活正版\",点击确定将会发送一条6元短信,不含信息费.",
"发送成功!已成功解锁!",true);
}else{
Log.e(TAG, "----------------->>> ppw close <<<------------------");
}
ppw.dismiss();
}
};
View v = LayoutInflater.from(mContext).inflate(R.layout.layout_ctdialog, null);
TextView tv = (TextView) v.findViewById(R.id.ct_dialogtext);
Button bty = (Button) v.findViewById(R.id.ct_dlg_yes);
Button btn = (Button) v.findViewById(R.id.ct_dlg_no);
ImageButton imbt=(ImageButton)v.findViewById(R.id.ct_dlg_close);
tv.setText("仅需支付6元,即可享受正版游戏!感谢支持正版!");
bty.setOnClickListener(cl);
btn.setOnClickListener(cl);
imbt.setOnClickListener(cl);
ppw.setBackgroundDrawable(new ColorDrawable(Color.BLACK));
ppw.setContentView(v);
ppw.setOutsideTouchable(false);
ppw.setFocusable(true);
ppw.update();
ppw.showAsDropDown(v,(int)w/2,(int)h/2);
}
Android PopupWindow 增加半透明蒙层
先看效果图:
BasePopupWindowWithMask.class
1 package com.example.popupwindowwithmask;
2
3 import android.content.Context;
4 import android.graphics.PixelFormat;
5 import android.graphics.drawable.ColorDrawable;
6 import android.os.IBinder;
7 import android.view.KeyEvent;
8 import android.view.View;
9 import android.view.WindowManager;
10 import android.widget.PopupWindow;
11
12 /**
13 * Created by kk on 2017/7/22.
14 */
15
16 public abstract class BasePopupWindowWithMask extends PopupWindow {
17 protected Context context;
18 private WindowManager windowManager;
19 private View maskView;
20
21 public BasePopupWindowWithMask(Context context) {
22 super(context);
23 this.context = context;
24 windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
25 setContentView(initContentView());
26 setHeight(initHeight());
27 setWidth(initWidth());
28 setOutsideTouchable(true);
29 setFocusable(true);
30 setTouchable(true);
31 setBackgroundDrawable(new ColorDrawable());
32 }
33
34 protected abstract View initContentView();
35
36 protected abstract int initHeight();
37
38 protected abstract int initWidth();
39
40 @Override
41 public void showAsDropDown(View anchor) {
42 addMask(anchor.getWindowToken());
43 super.showAsDropDown(anchor);
44 }
45
46 private void addMask(IBinder token) {
47 WindowManager.LayoutParams wl = new WindowManager.LayoutParams();
48 wl.width = WindowManager.LayoutParams.MATCH_PARENT;
49 wl.height = WindowManager.LayoutParams.MATCH_PARENT;
50 wl.format = PixelFormat.TRANSLUCENT;//不设置这个弹出框的透明遮罩显示为黑色
51 wl.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;//该Type描述的是形成的窗口的层级关系
52 wl.token = token;//获取当前Activity中的View中的token,来依附Activity
53 maskView = new View(context);
54 maskView.setBackgroundColor(0x7f000000);
55 maskView.setFitsSystemWindows(false);
56 maskView.setOnKeyListener(new View.OnKeyListener() {
57 @Override
58 public boolean onKey(View v, int keyCode, KeyEvent event) {
59 if (keyCode == KeyEvent.KEYCODE_BACK) {
60 removeMask();
61 return true;
62 }
63 return false;
64 }
65 });
66 /**
67 * 通过WindowManager的addView方法创建View,产生出来的View根据WindowManager.LayoutParams属性不同,效果也就不同了。
68 * 比如创建系统顶级窗口,实现悬浮窗口效果!
69 */
70 windowManager.addView(maskView, wl);
71 }
72
73 private void removeMask() {
74 if (null != maskView) {
75 windowManager.removeViewImmediate(maskView);
76 maskView = null;
77 }
78 }
79
80 @Override
81 public void dismiss() {
82 removeMask();
83 super.dismiss();
84 }
85 }
TestPopupWindow.class
1 package com.example.popupwindowwithmask;
2
3 import android.content.Context;
4 import android.view.LayoutInflater;
5 import android.view.View;
6 import android.view.WindowManager;
7
8 /**
9 * Created by kk on 2017/7/22.
10 */
11
12 public class TestPopupWindow extends BasePopupWindowWithMask {
13 private int[] mIds;
14 private View contentView;
15 private OnItemClickListener listener;
16
17 public interface OnItemClickListener {
18 void OnItemClick(View v);
19 }
20
21 public void setOnItemClickListener(OnItemClickListener listener) {
22 this.listener = listener;
23 }
24
25 public TestPopupWindow(Context context, int[] mIds) {
26 super(context);
27 this.mIds = mIds;
28
29 initListener();
30 }
31
32 @Override
33 protected View initContentView() {
34 contentView = LayoutInflater.from(context).inflate(R.layout.pop_layout, null, false);
35 return contentView;
36 }
37
38 private void initListener() {
39 for (int i = 0; i < mIds.length; i++) {
40 contentView.findViewById(mIds[i]).setOnClickListener(new View.OnClickListener() {
41 @Override
42 public void onClick(View v) {
43 if (null != listener) {
44 listener.OnItemClick(v);
45 }
46 dismiss();
47 }
48 });
49 }
50 }
51 @Override
52 protected int initHeight() {
53 return WindowManager.LayoutParams.WRAP_CONTENT;
54 }
55 @Override
56 protected int initWidth() {
57 return (int) (0.5 * UIUtils.getScreenWidth(context));
58 }
59 }
60 MainActivity.class
61 ?
62 1
63 2
64 3
65 4
66 5
67 6
68 7
69 8
70 9
71 10
72 11
73 12
74 13
75 14
76 15
77 16
78 17
79 18
80 19
81 20
82 21
83 22
84 23
85 24
86 25
87 26
88 27
89 28
90 29
91 30
92 31
93 32
94 33
95 34
96 35
97 36
98 37
99 38
100 39
101 40
102 41
103 42
104 43
105 44
106 45
107 package com.example.popupwindowwithmask;
108
109 import android.os.Bundle;
110 import android.support.v7.app.AppCompatActivity;
111 import android.view.View;
112 import android.widget.TextView;
113 import android.widget.Toast;
114
115 public class MainActivity extends AppCompatActivity {
116 private TextView textView;
117
118 @Override
119 protected void onCreate(Bundle savedInstanceState) {
120 super.onCreate(savedInstanceState);
121 setContentView(R.layout.activity_main);
122 textView = (TextView) findViewById(R.id.tv_popup);
123
124
125 final TestPopupWindow testPopupWindow = new TestPopupWindow(this, new int[]{R.id.pop_location, R.id.pop_group, R.id.pop_list});
126
127 textView.setOnClickListener(new View.OnClickListener() {
128 @Override
129 public void onClick(View v) {
130 testPopupWindow.showAsDropDown(textView);
131 }
132 });
133
134 testPopupWindow.setOnItemClickListener(new TestPopupWindow.OnItemClickListener() {
135 @Override
136 public void OnItemClick(View v) {
137 switch (v.getId()) {
138 case R.id.pop_location:
139 Toast.makeText(MainActivity.this, "地址", Toast.LENGTH_SHORT).show();
140 break;
141 case R.id.pop_group:
142 Toast.makeText(MainActivity.this, "分组", Toast.LENGTH_SHORT).show();
143 break;
144 case R.id.pop_list:
145 Toast.makeText(MainActivity.this, "清单", Toast.LENGTH_SHORT).show();
146 break;
147 }
148 }
149 });
150 }
151 }
pop_layout.xml
1 <?xml version="1.0" encoding="utf-8"?>
2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="wrap_content"
4 android:layout_height="wrap_content">
5
6 <RelativeLayout
7 android:layout_width="wrap_content"
8 android:layout_height="wrap_content">
9
10 <RelativeLayout
11 android:id="@+id/rl_indicator"
12 android:layout_width="match_parent"
13 android:layout_height="wrap_content"
14 android:gravity="center_horizontal">
15
16 <ImageView
17 android:layout_width="wrap_content"
18 android:layout_height="12dp"
19 android:scaleType="fitCenter"
20 android:src="@drawable/filter_arrow_up" />
21 </RelativeLayout>
22
23 <LinearLayout
24 android:layout_width="wrap_content"
25 android:layout_height="150dp"
26 android:layout_below="@+id/rl_indicator"
27 android:background="@drawable/pop_background"
28 android:gravity="center_horizontal"
29 android:orientation="vertical"
30 android:paddingLeft="15dp"
31 android:paddingRight="15dp">
32
33 <TextView
34 android:id="@+id/pop_location"
35 android:layout_width="match_parent"
36 android:layout_height="0dp"
37 android:layout_weight="1"
38 android:drawableLeft="@mipmap/fault_equipment_location_icon"
39 android:drawablePadding="12dp"
40 android:gravity="center_vertical"
41 android:text="地址"
42 android:textColor="#000"
43 android:textSize="16sp" />
44
45 <View
46 android:layout_width="match_parent"
47 android:layout_height="0.3dp"
48 android:background="#D2D2D2" />
49
50 <TextView
51 android:id="@+id/pop_group"
52 android:layout_width="match_parent"
53 android:layout_height="0dp"
54
55 android:layout_weight="1"
56 android:drawableLeft="@mipmap/fault_equipment_grouping_icon"
57 android:drawablePadding="12dp"
58 android:gravity="center_vertical"
59 android:text="分组"
60 android:textColor="#000"
61 android:textSize="16sp" />
62
63 <View
64 android:layout_width="match_parent"
65 android:layout_height="0.3dp"
66 android:background="#D2D2D2" />
67
68 <TextView
69 android:id="@+id/pop_list"
70 android:layout_width="match_parent"
71 android:layout_height="0dp"
72 android:layout_weight="1"
73 android:drawableLeft="@mipmap/fault_equipment_list_icon"
74 android:drawablePadding="12dp"
75 android:gravity="center_vertical"
76 android:text="清单"
77 android:textColor="#000"
78 android:textSize="16sp" />
79
80 </LinearLayout>
81 </RelativeLayout>
82 </RelativeLayout>
pop_background.xml
1 <?xml version="1.0" encoding="utf-8"?>
2 <shape xmlns:android="http://schemas.android.com/apk/res/android">
3 <solid android:color="#ffffff" />
4 <corners
5 android:radius="5dp" />
6 </shape>
UIUtils.class
1 package com.example.popupwindowwithmask;
2
3 import android.content.Context;
4
5 /**
6 * Created by kk on 2017/7/22.
7 */
8
9 public class UIUtils {
10 /**
11 * 获得屏幕宽度
12 *
13 * @param context
14 * @return
15 */
16 public static int getScreenWidth(Context context) {
17 return context.getResources().getDisplayMetrics().widthPixels;
18 }
19
20 /**
21 * 获得屏幕高度
22 *
23 * @param context
24 * @return
25 */
26 public static int getScreenHeight(Context context) {
27 return context.getResources().getDisplayMetrics().heightPixels;
28 }
29
30 }
https://github.com/ganchuanpu/AndroidPopupWindowWithMask.git
我们今天的关于PopupWindow重叠Android 5.0上的软按钮的分享已经告一段落,感谢您的关注,如果您想了解更多关于Android 7.0 PopupWindow 显示错位问题、Android 7.0 PopupWindow 错位移位问题、android popupWindow、Android PopupWindow 增加半透明蒙层的相关信息,请在本站查询。
本文标签: