Android 动态毛玻璃背景的简单实现(高斯模糊)

Android 动态毛玻璃背景的简单实现(高斯模糊)

做APP的时候,UI总是会搞一些这种高斯模糊的效果,为了方便使用,简单讲一下怎么实现,以及提供封装好的View。
我这里是采用RenderScript来实现的高斯模糊,RenderScript 是用于在 Android 上以高性能运行计算密集型任务的框架,性能比较能满足需求。

大概效果如下,可以看一下是否满足你的需求

效果预览

实现步骤

实现步骤大概可以分为三步

  1. 截取需要模糊的区域的背景
  2. 对截取到的bitmap进行高斯模糊处理
  3. 为ImageView设置Bitmap

先新建一个类BlurBGImageView继承自ImageView,然后一步步实现下面的方法,完整代码在文末

截取对应的背景图方法

/**
*view 需要截取的背景View,在效果图中就是后面的recycleView
*/
private Bitmap getBitmap(View view){
        //获取屏幕整张图片
        Bitmap bitmap = view.getDrawingCache();

        if (bitmap != null) {

            //需要截取的长和宽
            int outWidth = this.getWidth();
            int outHeight = this.getHeight();

            //获取需要截图部分的在屏幕上的坐标(view的左上角坐标)
            int[] viewLocationArray = new int[2];
            this.getLocationOnScreen(viewLocationArray);
            //背景View所在屏幕上的坐标
            int[] listLocationArray = new int[2];
            view.getLocationOnScreen(listLocationArray);

            //从屏幕整张图片中截取指定区域
            bitmap = Bitmap.createBitmap(bitmap, viewLocationArray[0] - listLocationArray[0], viewLocationArray[1]  - listLocationArray[1], outWidth, outHeight);

        }

        return bitmap;
    }

对图片进行高斯模糊然后setImageBitmap设置

    /**
    *radius 模糊半径
    **/
    private void blur(Bitmap bkg, ImageView view, float radius) {
        if (overlay != null){
            overlay.recycle();
        }
        //图片的大小很影响高斯模糊的速度,所以我们对图片先进行缩放,scaleFactor为缩放的倍数
        overlay = Bitmap.createScaledBitmap(bkg, bkg.getWidth() / scaleFactor, bkg.getHeight() / scaleFactor, false);
        overlay = blur(getContext(),overlay, radius);//高斯模糊
        view.setImageBitmap(overlay);
    }
    
    private Bitmap blur(Context context, Bitmap image, float radius) {
        RenderScript rs = RenderScript.create(context);
        Bitmap outputBitmap = Bitmap.createBitmap(image.getWidth(), image.getHeight(), Bitmap.Config.ARGB_8888);
        Allocation in = Allocation.createFromBitmap(rs, image);
        Allocation out = Allocation.createFromBitmap(rs, outputBitmap);

        ScriptIntrinsicBlur intrinsicBlur = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
        intrinsicBlur.setRadius(radius);
        intrinsicBlur.setInput(in);
        intrinsicBlur.forEach(out);

        out.copyTo(outputBitmap);
        image.recycle();
        rs.destroy();
        return outputBitmap;
    }

好了,最后我们再对外开放一个方法,供外部调用就可以了

    /**
    *bgView 从外部传入的背景View
    **/
    public void refreshBG(View bgView){
        bgView.setDrawingCacheEnabled(true);
        bgView.buildDrawingCache();
        Bitmap bitmap1 = null;
        try {
            bitmap1 = getBitmap(bgView);
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (bitmap1 != null){
            blur(bitmap1,this,radius);//模糊处理
            bitmap1.recycle();
        }
        bgView.setDrawingCacheEnabled(false);//清除缓存
    }

完整代码

XML处调用

    <com.lpoint.widget.BlurBGImageView
        android:id="@+id/img_vague"
        android:layout_width="300dp"
        android:layout_centerInParent="true"
        android:layout_height="200dp"/>

完整的BlurBGImageView类


import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RenderScript;
import android.renderscript.ScriptIntrinsicBlur;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;

import androidx.annotation.Nullable;

@SuppressLint("AppCompatCustomView")
public class BlurBGImageView extends ImageView {
    Bitmap overlay;
    int scaleFactor = 2;
    int radius = 8;
    public BlurBGImageView(Context context) {
        super(context);
    }

    public BlurBGImageView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public BlurBGImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public void setScaleFactor(int scaleFactor) {
        this.scaleFactor = scaleFactor;
    }


    public void refreshBG(View bgView){
        bgView.setDrawingCacheEnabled(true);
        bgView.buildDrawingCache();
        Bitmap bitmap1 = null;
        try {
            bitmap1 = getBitmap(bgView);
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (bitmap1 != null){
            blur(bitmap1,this,radius);//模糊处理
            bitmap1.recycle();
        }
        bgView.setDrawingCacheEnabled(false);//清除缓存
    }

    private void blur(Bitmap bkg, ImageView view, float radius) {
        if (overlay != null){
            overlay.recycle();
        }
        overlay = Bitmap.createScaledBitmap(bkg, bkg.getWidth() / scaleFactor, bkg.getHeight() / scaleFactor, false);
        overlay = blur(getContext(),overlay, radius);//高斯模糊
        view.setImageBitmap(overlay);
    }

    private Bitmap blur(Context context, Bitmap image, float radius) {
        RenderScript rs = RenderScript.create(context);
        Bitmap outputBitmap = Bitmap.createBitmap(image.getWidth(), image.getHeight(), Bitmap.Config.ARGB_8888);
        Allocation in = Allocation.createFromBitmap(rs, image);
        Allocation out = Allocation.createFromBitmap(rs, outputBitmap);

        ScriptIntrinsicBlur intrinsicBlur = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
        intrinsicBlur.setRadius(radius);
        intrinsicBlur.setInput(in);
        intrinsicBlur.forEach(out);

        out.copyTo(outputBitmap);
        image.recycle();
        rs.destroy();
        return outputBitmap;
    }
    private Bitmap getBitmap(View view){
        //获取屏幕整张图片
        Bitmap bitmap = view.getDrawingCache();

        if (bitmap != null) {

            //需要截取的长和宽
            int outWidth = this.getWidth();
            int outHeight = this.getHeight();

            //获取需要截图部分的在屏幕上的坐标(view的左上角坐标)
            int[] viewLocationArray = new int[2];


            this.getLocationOnScreen(viewLocationArray);

            int[] listLocationArray = new int[2];
            view.getLocationOnScreen(listLocationArray);

            //从屏幕整张图片中截取指定区域
            bitmap = Bitmap.createBitmap(bitmap, viewLocationArray[0] - listLocationArray[0], viewLocationArray[1]  - listLocationArray[1], outWidth, outHeight);

        }

        return bitmap;
    }
}

最后在Activity里面调用(建议调用间隔不小于30ms)

imgVague.refreshBG(recyclerView);

大功告成

实现高斯模糊背景的对话框,可以使用 Android 的 DialogFragment 和 RenderScript 实现。以下是大致的步骤: 1. 在布局文件中定义对话框的 UI,注意要为对话框添加一个半透明的背景。 2. 创建一个继承自 DialogFragment 的类,并在其中实现 onCreateDialog() 方法。 3. 在 onCreateDialog() 方法中,使用 RenderScript 创建一个高斯模糊的 Bitmap,并将其设置为对话框背景。 4. 在对话框显示时,使用 DialogFragment.show() 方法显示对话框。 以下是示例代码: ```java public class BlurDialogFragment extends DialogFragment { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { // 创建一个对话框 AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); LayoutInflater inflater = getActivity().getLayoutInflater(); View view = inflater.inflate(R.layout.dialog_layout, null); builder.setView(view); // 创建一个 RenderScript 对象 RenderScript rs = RenderScript.create(getActivity()); // 加载图片资源 Bitmap image = BitmapFactory.decodeResource(getResources(), R.drawable.background); // 创建一个高斯模糊的 Bitmap Bitmap blurredBitmap = image.copy(Bitmap.Config.ARGB_8888, true); Allocation input = Allocation.createFromBitmap(rs, image); Allocation output = Allocation.createFromBitmap(rs, blurredBitmap); ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); script.setInput(input); script.setRadius(25.f); script.forEach(output); output.copyTo(blurredBitmap); // 将高斯模糊的 Bitmap 设置为对话框背景 view.setBackground(new BitmapDrawable(getResources(), blurredBitmap)); return builder.create(); } } ``` 要实现毛玻璃效果的对话框,可以使用 Android 的 DialogFragment 和自定义控件实现。以下是大致的步骤: 1. 在布局文件中定义对话框的 UI,包括一个用于显示毛玻璃效果的自定义控件。 2. 创建一个继承自 DialogFragment 的类,并在其中实现 onCreateDialog() 方法。 3. 在 onCreateDialog() 方法中,创建一个自定义控件的实例,并将其添加到对话框的 UI 中。 4. 在对话框显示时,使用 DialogFragment.show() 方法显示对话框。 以下是示例代码: ```java public class GlassDialogFragment extends DialogFragment { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { // 创建一个对话框 AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); LayoutInflater inflater = getActivity().getLayoutInflater(); View view = inflater.inflate(R.layout.dialog_layout, null); builder.setView(view); // 创建一个自定义控件 GlassView glassView = new GlassView(getActivity()); ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); glassView.setLayoutParams(layoutParams); // 将自定义控件添加到对话框的 UI 中 FrameLayout frameLayout = view.findViewById(R.id.frame_layout); frameLayout.addView(glassView); return builder.create(); } } ``` 其中 GlassView 是一个自定义控件,用于显示毛玻璃效果。以下是示例代码: ```java public class GlassView extends View { private Paint paint = new Paint(); private Bitmap bitmap; public GlassView(Context context) { super(context); init(); } public GlassView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public GlassView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { // 加载图片资源 bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.background); // 设置画笔透明度 paint.setAlpha(100); } @Override protected void onDraw(Canvas canvas) { // 创建一个缩小的 Bitmap,用于实现毛玻璃效果 Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, bitmap.getWidth() / 10, bitmap.getHeight() / 10, false); // 将缩小的 Bitmap 放大,实现模糊效果 Bitmap blurredBitmap = Bitmap.createScaledBitmap(scaledBitmap, getWidth(), getHeight(), false); // 绘制模糊的 Bitmap canvas.drawBitmap(blurredBitmap, 0, 0, paint); } } ``` 注意:以上代码只是示例代码,实际上还需要根据具体情况进行调整和优化。
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值