测试小姐姐在华为手机上 PopupWindow弹出位置 直接置顶了,但是我的开发机(小米9)却按照代码的意志显示在titleBar之下。
效果类似这样:
谷歌一把 ,各种吐槽该问题。
大神们的主流解决方案,主要分两种,
①重写showAsDropDown(),以24为界限,区别对待;
②调用show的时候,SDK>24的时用showAtLocation()替代showAsDropDown();
我先把大婶们的各类终极版的方案代码贴出来:
@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);
}
或者
if (Build.VERSION.SDK_INT < 24) {
popupWindow.showAsDropDown(anchor);
} else {
int[] location = new int[2];
anchor.getLocationOnScreen(location);
int y = location[1];
popupWindow.showAtLocation(anchor, Gravity.NO_GRAVITY, 0, y + anchor.getHeight());
}
各种尝试,修改,然并卵,统统都不管用。
要么popupWin位置被顶上去,要么阴影底部有白边,要么是虚拟键滑动隐藏时,阴影底部露出白边,虚拟键动态显示时,popupWin被顶上去。各种终极版的方案,并未终结该问题。
显然是popupWin高度计算出问题了,不同手机现象不一,又是让人头大且脱发的适配问题,怎么办呢?
话不多说,直奔主题,我是如何解决的?
项目需求是要求上面是筛选弹窗,下层是列表,那么列表RecyclerView怎么做到不白边的?已知RecyclerView高度MATCH_PARENT,且PopupWin与背景RecyclerView等高,那我直接把RecyclerView高度设置给PopupWindow就好了。试了一下,果然完美终结该问题。
请看在华为荣耀8.安卓8.0系统上测试效果图:(请忽略该app是啥,这个不重要)
具体实现步骤
代码思路:
1.在popupWin.show 之前,把与她等高的View(此处指RecyclerView)高度通过setHeight赋值。等show时,高度就生效了;
2.当用户手动显示或隐藏虚拟键时候,需要根据与之等高View高度变化再次动态设置popuWin高度,此时一定是显示状态时候设置,如隐藏就不再考虑。
最重要的伪代码送上:
private void test() {
tvTitle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!popupWindow.isShowing()) {
//设置高度,不立即生效,调用show之后,才生效
popupWindow.setHeight(recyclerView.getHeight());
popupWindow.showAsDropDown(anchor);
} else {
popupWindow.dismiss();
}
}
});
//监听RecyclerView高度,动态赋值给popupWin
recyclerView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
if (popupWindow.isShowing()) {
//设置高度并生效
popupWindow.update(ViewGroup.LayoutParams.MATCH_PARENT, recyclerView.getHeight());
}
}
});
}