如何为居中显示的PopupWindow实现背景模糊效果?
我来给你几个实用的解决方案,帮你搞定在Fragment的RecyclerView Adapter里触发居中PopupWindow时,没法截取Activity UI做模糊背景的问题:
方案1:通过View获取根视图并截图
不需要直接持有Activity引用,你可以从点击的列表项View入手,拿到整个界面的根视图后再截图模糊,步骤如下:
- 从点击的item View中获取根视图(整个Activity的界面容器)
- 监听根视图的绘制完成事件,避免截图为空
- 截取根视图并做模糊处理,最后设置为PopupWindow的背景
代码示例:
holder.itemView.setOnClickListener(v -> { // 获取整个界面的根视图 View rootView = v.getRootView(); // 监听视图绘制完成,确保截图时界面已渲染完毕 rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { // 移除监听,防止重复触发 rootView.getViewTreeObserver().removeOnGlobalLayoutListener(this); // 截取根视图生成Bitmap Bitmap bitmap = Bitmap.createBitmap(rootView.getWidth(), rootView.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); rootView.draw(canvas); // 用你之前的fast blur工具处理模糊 Bitmap blurredBitmap = fastBlur(bitmap, 10); // 10为模糊半径,可调整 // 将模糊后的Bitmap转为Drawable作为弹窗背景 Drawable blurredBg = new BitmapDrawable(v.getResources(), blurredBitmap); // 创建并显示居中PopupWindow PopupWindow popupWindow = new PopupWindow(contentView, width, height); popupWindow.setBackgroundDrawable(blurredBg); popupWindow.showAtLocation(rootView, Gravity.CENTER, 0, 0); } }); });
这个方案的核心是利用View的getRootView()方法,绕开了直接获取Activity的限制,完美适配Fragment+Adapter的场景。
方案2:单独添加全局模糊遮罩层
如果不想把模糊效果绑定到PopupWindow的背景上,可以先给整个屏幕添加一层模糊遮罩,再显示PopupWindow,弹窗消失时移除遮罩:
- 通过Context获取WindowManager
- 创建覆盖全屏的模糊View,添加到WindowManager
- 显示PopupWindow,设置消失监听移除遮罩
代码示例:
holder.itemView.setOnClickListener(v -> { Context context = v.getContext(); WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); // 创建模糊遮罩View View blurMask = new View(context); // 先截取根视图并模糊 Bitmap rootBitmap = getRootBitmap(v); // 复用方案1的截图逻辑 Bitmap blurredBitmap = renderScriptBlur(context, rootBitmap); blurMask.setBackground(new BitmapDrawable(context.getResources(), blurredBitmap)); // 设置遮罩的布局参数 WindowManager.LayoutParams maskParams = new WindowManager.LayoutParams( WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN, PixelFormat.TRANSLUCENT ); windowManager.addView(blurMask, maskParams); // 创建并显示PopupWindow PopupWindow popupWindow = new PopupWindow(contentView, width, height); popupWindow.setOutsideTouchable(true); // 弹窗消失时移除遮罩 popupWindow.setOnDismissListener(() -> windowManager.removeView(blurMask)); popupWindow.showAtLocation(v.getRootView(), Gravity.CENTER, 0, 0); }); // 用RenderScript实现高效模糊的工具方法 private Bitmap renderScriptBlur(Context context, Bitmap inputBitmap) { RenderScript rs = RenderScript.create(context); Allocation input = Allocation.createFromBitmap(rs, inputBitmap); Allocation output = Allocation.createTyped(rs, input.getType()); ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); blurScript.setRadius(10f); blurScript.setInput(input); blurScript.forEach(output); output.copyTo(inputBitmap); rs.destroy(); return inputBitmap; }
这个方案的优势是模糊层和PopupWindow完全分离,适合需要动态调整模糊效果的复杂场景。
方案3:用第三方库简化实现
如果不想自己写截图和模糊的逻辑,可以用成熟的第三方库(比如BlurView),它已经封装了所有细节,只需要简单配置即可:
- 添加库依赖(以Gradle为例):
implementation 'com.github.Dimezis:BlurView:version' // 替换为最新版本号
- 在PopupWindow的布局中添加BlurView作为根布局:
<com.jakewharton.rxbinding4.view.RxView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content"> <com.google.android.material.blur.BlurView android:id="@+id/popup_blur_view" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- 你的弹窗内容布局 --> </com.google.android.material.blur.BlurView> </com.jakewharton.rxbinding4.view.RxView>
- 在Adapter的点击事件中配置BlurView:
holder.itemView.setOnClickListener(v -> { View contentView = LayoutInflater.from(v.getContext()).inflate(R.layout.popup_layout, null); BlurView blurView = contentView.findViewById(R.id.popup_blur_view); // 配置模糊参数,指定要模糊的根视图 blurView.setupWith(v.getRootView()) .setBlurAlgorithm(new RenderScriptBlur(v.getContext())) .setBlurRadius(10f) .setBlurAutoUpdate(true); // 创建并显示PopupWindow PopupWindow popupWindow = new PopupWindow(contentView, width, height); popupWindow.setOutsideTouchable(true); popupWindow.showAtLocation(v.getRootView(), Gravity.CENTER, 0, 0); });
这个方案最省心,库已经处理了截图、模糊、适配等所有问题,适合快速开发。
内容的提问来源于stack exchange,提问作者JimJay Lee
相关产品推荐
相关产品推荐

