关于安卓毛玻璃实现(三)recyclerview静态毛玻璃

背景

毛玻璃,开发中又爱又恨的一个话题,玩法层出不穷,有动态的,也有静态的。有的是实时模糊,有些只需要模糊一次,本文的毛玻璃实现,就是静态毛玻璃。

开发环境

win 10
as 4+
jdk 1.8

代码

!!!源码在文末!!!

最终效果

关于安卓毛玻璃实现(三)recyclerview静态毛玻璃_第1张图片

思路

看到上图,首先就要观察有什么要点:
(1)毛玻璃的区域,是与图片“内容连贯”的,就是说,毛玻璃展示内容,和实际内容一致,视觉上就是“局部毛玻璃”的效果。
(2)毛玻璃的形状,看上去,毛玻璃四个角都是圆角,所以,就涉及到毛玻璃展示过程中的圆角绘制。

根据要点,可以总结出,原图,必须要先加载出来,然后设置到ImageView上面,再获取ImageView正在显示的图像(先设置到ImageView,因为会收到其ScaleType属性影响),然后自定义view对获取的图片进行处理即可。

实现

原理说完了,那又要怎么实现呢?列出步骤:
(一)把图片显示在背景控件上面
(二)把背景控件显示后的图片,传入到自定义毛玻璃控件中
(三)通过canvas处理,绘制,显示
下面开始具体描述如何实现:

(一)把图片显示在背景控件上面

这一步就是常规操作了,可以用glide,也可以本地随便搞一个图片设置到背景控件中即可,笔者这里的demo是通过ImageView xml属性配置的。

(二)把背景控件显示后的图片,传入到自定义毛玻璃控件中

这里就涉及到一个“获取显示控件的图片”这一个逻辑,具体的实现代码如下:


    /**
     * 普通截图
     */
    public static void viewSnapShot(View view, ViewSnapListener listener) {
        try {
            //使控件可以进行缓存
            view.setDrawingCacheEnabled(true);
            //获取缓存的 Bitmap
            Bitmap drawingCache = view.getDrawingCache();
            //复制获取的 Bitmap
            drawingCache = Bitmap.createBitmap(drawingCache, 0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
            //关闭视图的缓存
            view.setDrawingCacheEnabled(false);
            view.destroyDrawingCache();
            if (drawingCache != null) {
                if (listener != null) {
                    listener.success(drawingCache);
                }
            } else {
                if (listener != null) {
                    listener.failed("draw cache is null");
                }
            }
        } catch (Exception e) {
            if (listener != null) {
                listener.failed(e.getMessage());
            }
        }
    }

通过该方法,可以获取ImageView控件显示中的图片,并且返回一个bitmap对象给外部了。

(三)通过canvas处理,绘制,显示

这里涉及到自定义view。首先,先看xml设置的布局位置,代码如下:

        

            

            

        

可以看到,自定义毛玻璃控件BlurAlignBottomView的宽高是与背景图片显示控件的宽高一样的。

再说核心实现。因为宽高一样,所以处理起来,就简单很多了。
(1)通过clipRect方法,剪裁不需要显示的区域
(2)最后把bitmap高斯模糊后通过canvas画上去

对bitmap进行高斯模糊的代码如下:

    public static Bitmap blur(Context context,int blurRadius, Bitmap srcBitmap) {
        try {
            float radius = Math.min(25,blurRadius);
            radius = Math.max(0,radius);
            Bitmap bitmap = srcBitmap.copy(srcBitmap.getConfig(), true);
            final RenderScript rs = RenderScript.create(context);
            final Allocation input = Allocation.createFromBitmap(rs, srcBitmap,
                    Allocation.MipmapControl.MIPMAP_NONE,
                    Allocation.USAGE_SCRIPT);
            final Allocation output = Allocation.createTyped(rs, input.getType());
            final ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
            script.setRadius(radius /* e.g. 3.f */);
            script.setInput(input);
            script.forEach(output);
            output.copyTo(bitmap);
            return bitmap;
        } catch (Exception e) {
            e.printStackTrace();
            return srcBitmap;
        }
    }

使用原生RenderScript模糊即可。

剪裁显示范围以及绘制bitmap核心代码如下:

            int mesWidth = getMeasuredWidth();
            int mesHeight = getMeasuredHeight();
            float radius = mBlurInfo.getRadius();

            Bitmap mSrcBitmap = mBlurInfo.getSrcBitmap();

            canvas.save();

            canvas.clipRect(0, mesHeight - mBlurInfo.getBlurHeight(), mesWidth, mesHeight);

            RectF canvasRectF = new RectF(0, mesHeight - mBlurInfo.getBlurHeight(), mesWidth, mesHeight);
            Path mPath = new Path();
            mPath.addRoundRect(canvasRectF, radius, radius, Path.Direction.CW);
            canvas.clipPath(mPath);

            Rect bitmapRect = new Rect(0, 0, mesWidth, mesHeight);
            canvas.drawBitmap(mSrcBitmap, null, bitmapRect, null);


            canvas.restore();
        }

总结。实现方式其实用很多,而文中的实现方式,仅仅是众多方法中的一种而已,各位若有更好的方法请在评论区留言。

代码地址
搜索BlurAlignBottomView类

that’s all----------------------------------------------------------------------------

你可能感兴趣的:(安卓实战,图片处理,android,ui,java)