Android 7.0 PopupWindow 又引入新的问题,Google工程师也不够仔细么
2017-03-22 14:30
405 查看
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.cn 1202b
blogs.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这个控件
本来2017年回来还没有时间写写文章,这篇文章也是巧合,同事在
Android7.0中发现
PopupWindow使用上有
bug,所以我就借此机会研究一下,虽然知识点简单,但是也花费了几个小时的时间整理出这样一篇文章。如果读者觉得有用,别忘记点击推荐哦,总之也算是开了一个好头吧,以后还是会坚持每个月写些文章出来分享。
相关文章推荐
- Android 7.0 PopupWindow 又引入新的问题,Google工程师也不够仔细么
- Android 7.0 PopupWindow弹出位置的适配问题
- Android PopupWindow 7.0之后出现的问题
- Android中PopupWindow 在 Android N(7.0) 的兼容性问题
- PopupWindow 在 Android N(7.0) 的兼容性问题
- Android 7.0 popupwindow位置问题
- 解决在Android 7.0上PopupWindow.showAsDropDown不起作用的问题
- Android 6.0+ RecyclerView嵌套在ScrollView显示不全以及Android 7.0+ PopupWindow位置显示不对的问题解决
- Android 开发 Tip 18 -- PopupWindow 在 Android N(7.0)及以上 的兼容性问题
- PopupWindow的showAsDropDown位置问题 Android7.0
- 【多图】Google工程师解析Android系统架构
- 想成为Google工程师?先回答这15个面试问题【这只是一必要条件】(三)
- 想成为Google工程师?先回答这15个面试问题
- 关于android popupwindow 点击窗外不能关闭问题
- 不惧分裂 Google解决Android屏幕尺寸问题
- Android 中 PopupWindow 响应返回键并关闭的问题
- 想成为Google工程师?先回答这15个面试问题【这只是一必要条件】(六)
- Google资深工程师详解Android的系统架构
- Google解决Android屏幕尺寸问题
- 想成为Google工程师?先回答这15个面试问题【这只是一必要条件】(四)