美文网首页Android 开发进阶
Android 做高斯模糊背景时,过渡的地方要求平滑的解决方案

Android 做高斯模糊背景时,过渡的地方要求平滑的解决方案

作者: JeffreyWorld | 来源:发表于2020-07-15 18:09 被阅读0次

    拿到一个小说详情页的设计稿,顶部要用小说的封面图做高斯模糊。然后在与下半部分界面过渡时,要保持平滑过渡。一般像小说的封面和音乐的专辑封面之类的图片,拿到的图片深色系、浅色系的都会有,以及各种排版的图片都有,要保障所有图片显示都没问题。写篇文章,记录下实现过程。

    此处需要平滑过渡 小说详情页设计稿

    一开始,尝试用图片直接做高斯模糊。但是会发现边缘处会有明显的分割线。很明显做不到,需求需要的过渡平滑。
    最后选择的解决方案如下:

    1. 将封面图用代码,直接裁剪一部分。
      Bitmap coverBitmap = BitmapUtils.cropBitmap(bitmap);
        /**
         * 裁剪中间
         *
         * @param srcBmp 原图
         * @return 裁剪后的图像
         */
        public static Bitmap cropBitmap(Bitmap srcBmp) {
            Bitmap dstBmp;
            if (srcBmp.getWidth() >= srcBmp.getHeight()){
    
                dstBmp = Bitmap.createBitmap(
                        srcBmp,
                        srcBmp.getWidth()/2 - srcBmp.getHeight()/2,
                        0,
                        srcBmp.getHeight(),
                        srcBmp.getHeight()
                );
    
            }else{
    
                dstBmp = Bitmap.createBitmap(
                        srcBmp,
                        0,
                        srcBmp.getHeight()/2 - srcBmp.getWidth()/2,
                        srcBmp.getWidth(),
                        srcBmp.getWidth()
                );
            }
            return dstBmp;
        }
    
    1. 将一个纯白色的长方形图(用代码生成也可以),拿到的 bitmap 与用封面图裁剪的图,做上下拼接。
    whiteRectBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.white_rect)
    newBitmap = BitmapUtils.combineImage(coverBitmap, whiteRectBitmap);
        /**
         * 拼接图片
         *
         * @param bitmaps 原图片集
         * @return  拼接后的新图
         */
        public static Bitmap combineImage(Bitmap... bitmaps) {
            boolean isMultiWidth = false;//是否为多宽度图片集
            int width = 0;
            int height = 0;
    
            //获取图纸宽度
            for (Bitmap bitmap : bitmaps) {
                if (width != bitmap.getWidth()) {
                    if (width != 0) {//过滤掉第一次不同
                        isMultiWidth = true;
                    }
                    width = width < bitmap.getWidth() ? bitmap.getWidth() : width;
                }
            }
    
            //获取图纸高度
            for (Bitmap bitmap : bitmaps) {
                if (isMultiWidth) {
                    height = height + bitmap.getHeight() * width / bitmap.getWidth();
                } else {
                    height = height + bitmap.getHeight();
                }
            }
    
            //创建图纸
            Bitmap newBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            //创建画布,并绑定图纸
            Canvas canvas = new Canvas(newBitmap);
            int tempHeight = 0;
            //画图
            for (int i = 0; i < bitmaps.length; i++) {
                if (isMultiWidth) {
                    if (width != bitmaps[i].getWidth()) {
                        int newSizeH = bitmaps[i].getHeight() * width / bitmaps[i].getWidth();
                        Bitmap newSizeBmp = resizeBitmap(bitmaps[i], width, newSizeH);
                        canvas.drawBitmap(newSizeBmp, 0, tempHeight, null);
                        tempHeight = tempHeight + newSizeH;
                        newSizeBmp.recycle();
                    } else {
                        canvas.drawBitmap(bitmaps[i], 0, tempHeight, null);
                        tempHeight = tempHeight + bitmaps[i].getHeight();
                    }
                } else {
                    canvas.drawBitmap(bitmaps[i], 0, tempHeight, null);
                    tempHeight = tempHeight + bitmaps[i].getHeight();
                }
                bitmaps[i].recycle();
            }
            return newBitmap;
        }
    
        public static Bitmap resizeBitmap(Bitmap bitmap, int newWidth, int newHeight) {
            float scaleWidth = ((float) newWidth) / bitmap.getWidth();
            float scaleHeight = ((float) newHeight) / bitmap.getHeight();
            Matrix matrix = new Matrix();
            matrix.postScale(scaleWidth, scaleHeight);
            Bitmap bmpScale = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
            return bmpScale;
        }
    
    1. 将拼接后的图片,进行高斯模糊。
        /**
         * 高斯模糊
         * @param context
         * @param source
         * @param radius
         * @return
         */
        public static Bitmap rsBlur(Context context,Bitmap source,int radius){
            Bitmap inputBmp = source;
            RenderScript renderScript =  RenderScript.create(context);
            // Allocate memory for Renderscript to work with
            final Allocation input = Allocation.createFromBitmap(renderScript,inputBmp);
            final Allocation output = Allocation.createTyped(renderScript,input.getType());
            // Load up an instance of the specific script that we want to use.
            ScriptIntrinsicBlur scriptIntrinsicBlur = ScriptIntrinsicBlur.create(renderScript, Element.U8_4(renderScript));
            scriptIntrinsicBlur.setInput(input);
            // Set the blur radius
            scriptIntrinsicBlur.setRadius(radius);
            // Start the ScriptIntrinisicBlur
            scriptIntrinsicBlur.forEach(output);
            // Copy the output to the blurred bitmap
            output.copyTo(inputBmp);
            renderScript.destroy();
            return inputBmp;
        }
    
    1. 最后,显示得到的高斯模糊后的图片,ImageView 可以加 android:alpha="0.3" 的透明度。
        /**
         * 显示顶部高斯模糊图片的背景
         * @param bitmap
         */
        private void showCoverBlur(Bitmap bitmap) {
            Bitmap coverBitmap = BitmapUtils.cropBitmap(bitmap);
            Bitmap whiteRectBitmap = BitmapUtils.drawable2Bitmap(getResources().getDrawable(R.drawable.white_rect));
            Bitmap newBitmap = BitmapUtils.combineImage(coverBitmap, whiteRectBitmap);
    
            Bitmap blurBitmap = BitmapUtils.rsBlur(BookDetailActivity.this, newBitmap, 25);
            iv_white_rect_blur.setImageBitmap(blurBitmap);
        }
    
    
    

    5.记得在onDestory里清空bitmap

        private void recycleBitmap(){
            if (coverBitmap != null && !coverBitmap.isRecycled()) {
                coverBitmap = null;
            }
            if (newBitmap != null && !newBitmap.isRecycled()) {
                newBitmap = null;
            }
            if (whiteRectBitmap != null && !whiteRectBitmap.isRecycled()) {
                whiteRectBitmap = null;
            }
            if (blurBitmap != null && !blurBitmap.isRecycled()) {
                blurBitmap = null;
            }
        }
    

    最后,显示的效果和设计稿想要的效果基本上是一致的。如果你也遇到类似需求,有其他更好的解决方案,欢迎留言交流。

    相关文章

      网友评论

        本文标题:Android 做高斯模糊背景时,过渡的地方要求平滑的解决方案

        本文链接:https://www.haomeiwen.com/subject/kkyjhktx.html