Android 如何让BottomSheet唤起的PopupWindow显示在其上方
提升PopupWindow的Z轴高度
Android 5.0及以上系统通过elevation属性控制View的Z轴层级,BottomSheet默认elevation一般为8dp,只需在PopupWindow初始化时设置更高的elevation即可,代码如下:tasksPriorityPopUp.setElevation(20f);
数值可根据实际效果调整,只要高于BottomSheet的elevation就不会被遮挡。修正LayoutInflater的获取来源
当前使用ApplicationContext获取LayoutInflater,通过ApplicationContext加载的布局不会继承当前页面的视图层级参数,容易出现渲染异常,将初始化方法里的requireContext().getApplicationContext()改为requireContext()即可。补充PopupWindow背景设置
未给PopupWindow设置背景时,部分Android系统版本会出现层级渲染bug,哪怕需要透明背景也需要显式设置,代码如下:tasksPriorityPopUp.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));调整显示方法(备选方案)
如果以上方法都不生效,可以改用showAtLocation方法指定PopupWindow附着在BottomSheet的根视图上,避免附着在层级更低的视图上,代码示例:
priority.setOnClickListener(new View.OnClickListener() { @RequiresApi(api = Build.VERSION_CODES.KITKAT) @Override public void onClick(View v) { int[] location = new int[2]; v.getLocationOnScreen(location); // getView()获取的是BottomSheetFragment的根视图 tasksPriorityPopUp.showAtLocation(getView(), Gravity.NO_GRAVITY, location[0], location[1] + v.getHeight()); } });
修改后的完整代码示例
PopupWindow初始化方法
private void setUpPriorityPopUpWindow() { LayoutInflater inflater = (LayoutInflater) requireContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); @SuppressLint("InflateParams") View v = inflater.inflate(R.layout.tasks_priority_popup_window,null); tasksPriorityPopUp = new PopupWindow(v, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT,true); // 设置高于BottomSheet的Z轴高度 tasksPriorityPopUp.setElevation(20f); // 显式设置背景避免渲染异常 tasksPriorityPopUp.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); }
点击事件调用逻辑
ImageButton priority = v.findViewById(R.id.priority); setUpPriorityPopUpWindow(); priority.setOnClickListener(new View.OnClickListener() { @RequiresApi(api = Build.VERSION_CODES.KITKAT) @Override public void onClick(View v) { // 优先使用原有showAsDropDown方法,层级异常时再切换为showAtLocation tasksPriorityPopUp.showAsDropDown(v); } });
内容的提问来源于stack exchange,提问作者Niranjan Ravikumar

