Android 动态毛玻璃背景的简单实现(高斯模糊)
做APP的时候,UI总是会搞一些这种高斯模糊的效果,为了方便使用,简单讲一下怎么实现,以及提供封装好的View。
我这里是采用RenderScript来实现的高斯模糊,RenderScript 是用于在 Android 上以高性能运行计算密集型任务的框架,性能比较能满足需求。
大概效果如下,可以看一下是否满足你的需求
实现步骤
实现步骤大概可以分为三步
- 截取需要模糊的区域的背景
- 对截取到的bitmap进行高斯模糊处理
- 为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);