背景
前期做项目实现了一个自定义键盘的控件,主要是通过extends PopupWindow来实现,后期我会考虑把这个自定义键盘开源,敬请关注。其中用到了PopupWindow.update( )方法,在Android7.0正式发布前,即在Android7.0以下的系统上没有问题,最近Android7.0的手机已经陆续进入市场。
就在这几天,有同事反应我们项目里面那个自定义键盘原来在界面底部,是正常,但是在Android7.0系统上就跑到界面顶部了,不正常了。
如下图,第1张图是不正常的,第2张图是正常的。
原因
1.自定义键盘的布局。初步从自定义键盘的布局入手,检查是否由布局引起,经过再三调试发现,布局没有问题。
2.断点调试。
public void show(View parent){
if (parent != null) {
mPopupWindow.showAtLocation(parent, Gravity.BOTTOM, 0, 0);
}
mPopupWindow.update();
}
调试这个方法,发现问题出在PopupWindow.update( )这里。
PopupWindow.update( )是做什么的呢?查看源码,系统解释是:
Updates the state of the popup window, if it is currently being displayed,from the currently set state.
中文意思:更新PopupWindow状态,如果当前已是显示状态,就从当前状态更新。
Android7.0以下的系统:
public void update() {
if (!isShowing() || mContentView == null) {
return;
}
WindowManager.LayoutParams p = (WindowManager.LayoutParams)
mPopupView.getLayoutParams();
boolean update = false;
final int newAnim = computeAnimationResource();
if (newAnim != p.windowAnimations) {
p.windowAnimations = newAnim;
update = true;
}
final int newFlags = computeFlags(p.flags);
if (newFlags != p.flags) {
p.flags = newFlags;
update = true;
}
if (update) {
setLayoutDirectionFromAnchor();
mWindowManager.updateViewLayout(mPopupView, p);
}
}
Android7.0系统:
public void update() {
if (!isShowing() || mContentView == null) {
return;
}
final WindowManager.LayoutParams p = (WindowManager.LayoutParams) mDecorView.getLayoutParams();
boolean update = false;
final int newAnim = computeAnimationResource();
if (newAnim != p.windowAnimations) {
p.windowAnimations = newAnim;
update = true;
}
final int newFlags = computeFlags(p.flags);
if (newFlags != p.flags) {
p.flags = newFlags;
update = true;
}
final int newGravity = computeGravity();
if (newGravity != p.gravity) {
p.gravity = newGravity;
update = true;
}
if (update) {
setLayoutDirectionFromAnchor();
mWindowManager.updateViewLayout(mDecorView, p);
}
}
经过对比发现,主要区别是下面这段代码:
final int newGravity = computeGravity();
if (newGravity != p.gravity) {
p.gravity = newGravity;
update = true;
}
接下来我们再看computeGravity()这个方法
private int computeGravity() {
int gravity = Gravity.START | Gravity.TOP;
if (mClipToScreen || mClippingEnabled) {
gravity |= Gravity.DISPLAY_CLIP_VERTICAL;
}
return gravity;
}
在computeGravity()这个方法可以看出,在Android7.0系统上,调用PopupWindow.update( )方法会导致PopupWindow的位置出现在界面顶部,而不是我们自己定义的位置,如:界面底部。
解决办法
PopupWindow.update( )在自定义键盘根本没有起到实质作用,注释掉即可。如下:
public void show(View parent){
if (parent != null) {
mPopupWindow.showAtLocation(parent, Gravity.BOTTOM, 0, 0);
}
// mPopupWindow.update(); //因android7.0此方法有改动,不适用android7.0系统以下使用,所以不再调用此方法
}