今天我想介绍的是一个用于截屏并实现高斯模糊的一个工具类。提到高斯模糊,有很多苹果用户一定不会太陌生吧!在苹果设备上很多都实现了高斯模糊的效果。例如下面的这张图,背景就是桌面的高斯模糊图。那么在Android中如何实现这样的效果的!哈哈,马上进行揭晓。
代码框架
从上面我们可以看到整个高斯模糊的东西很少,其中的代码量也很少。但是,通过这个高斯模糊我们能学到的东西确蛮多。
下面介绍一下各个类或者接口的具体是干些什么的吧:
GaussianBlur
:实现高斯模糊的核心类。BitmapSource
:原生(也就是没有经过高斯模糊处理的Bitmap)的Bitmap的来源的接口,所有获取原生Bitmap的类都要实现这个接口。CaptureByDraw
:一种通过View的draw()
方法来获取原生Bitmap的方法。CaptureByDrawingCache
:一种通过getDrawingCache()
方法来获取原生Bitmap的方法。- 没错代码就是这么出奇的简单,实现起来也特轻松。我们下面的学习把重点放在其它知识的扩展上。
代码具体分析
高斯模糊实现代码
/**
* 此类是进行高斯模糊的核心类
*/
public class GaussianBlur {
private BitmapSource bitmapSource;
private RenderScript renderScript;
private Bitmap bitmap;
private boolean isBlur = false;
private GaussianBlur() {
}
/**
* 此类用于设置获取原生Bitmap的方式
*
* @param bitmapSource
*/
public void setBitmapSource(BitmapSource bitmapSource) {
this.bitmapSource = bitmapSource;
}
/**
* 此类用于传入一个RenderScript对象
*
* @param renderScript
*/
public void setRenderScript(RenderScript renderScript) {
this.renderScript = renderScript;
}
/**
* 此类用于获取android.R.id.content父类View截图的高斯模糊图
*
* @param radius
* @return
*/
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
public Bitmap getGaussianBlurBitmap(@IntRange(from = 1, to = 25) int radius) {
if (!isBlur) {
isBlur = true;
//第一步,获取一个Bitmap(这里是一个UI的截图)
bitmap = bitmapSource.getBitmap();
//第二部,通过获取的Bitmap得到一个输入的Allocation和一个输出的Allocation
Allocation input = Allocation.createFromBitmap(renderScript, bitmap);
Allocation output = Allocation.createTyped(renderScript, input.getType());
//ScriptIntrinsicBlur是一个实现高斯模糊的具体类
ScriptIntrinsicBlur blur = ScriptIntrinsicBlur.create(renderScript, Element.U8_4(renderScript));
//进行高斯模糊操作
blur.setRadius(radius);
blur.setInput(input);
blur.forEach(output);
output.copyTo(bitmap);
}
return bitmap;
}
/**
* 进行单例,防止重复创建对象
*
* @return
*/
public static GaussianBlur getInstance() {
return GaussianBlurHolder.instance;
}
public static class GaussianBlurHolder {
private static final GaussianBlur instance = new GaussianBlur();
}
}
上面我们直接看到getGaussianBlurBitmap
方法。此方法是用来让原生的Bitmap实现高斯模糊的类。
- 第一步,
我们通过bitmapSource获取了一个Bitmap
。这是一种策略模式
,我们通过setBitmapSource()方法来设置了bitmapSource具体实现类。也就是这个类完全不会管bitmapSource是如何获取Bitmap的,你是截图来的,还是通过Drawable中的图片来的,我都不管,你只要给我一个Bitmap对象就对了。 - 第二步,我们通过上面获取的
Bitmap对象
和RenderScript环境
得到一个输入的Allocation
;然后,我们再通过输入的Allocation获得了一个输出的Allocation
。Allocation不知道是什么对吧!其实Allocation就可以想成是种货币,一种就要在rs文件(这里是指ScriptIntrinsicBlur对应的rs文件,其实ScriptIntrinsicBlur是由rs文件反射出来的一个Java类)中使用的货币 - 第三步,通过
ScriptIntrinsicBlur
类进行高斯模糊处理。注意setRaius值是1到25
,为了不让输入的时候输到范围之外,在参数上已经通过@IntRange
注解规定了其范围的。一旦超出范围就会报编译错误。
在介绍下面获取截屏的两个方法前,我们先来介绍一下Android的View的层级
下面是查看Android的View的层级的一个方法:
通过Layout Inspector
会出现下面的一个ViewTree
,通过这个我们可以很明了的分析咱们视图的层级
View的层级通过上面的工具已经可以很明了了,我就不单独再啰嗦了。
其中我们截屏所要的部分就是android.R.id.content所指代的View也就是上面的content
。
获取截图
通过View的draw方法获取截图
/**
* 此类为获取原生Bitmap的策略类
*/
public class CaptureByDraw implements BitmapSource {
private Activity activity;
public CaptureByDraw(Activity activity) {
this.activity = activity;
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
@Override
public Bitmap getBitmap() {
View contentView = (View) activity.findViewById(android.R.id.content);
Bitmap rawBitmap = Bitmap.createBitmap(contentView.getWidth(), contentView.getHeight(), Bitmap.Config.ARGB_4444);
contentView.draw(new Canvas(rawBitmap));
return rawBitmap;
}
}
- 第一步,我们通过
activity.findViewById(android.R.id.content)获取了上面所说的content这个View(其实是一个ViewGroup但是ViewGroup其实还是一View就不纠结了)
- 第二步,通过Bitmap的
createBitmap
方法获取一个Bitmap对象。 - 第三步,通过View的
draw
方法将其视图放在一个Bitmap中。
通过View的getDrawingCache方法获取截图
/**
* 此类是用于截图获得原生Bitmap的一个策略类
*/
public class CaptureByDrawingCache implements BitmapSource {
private Activity activity;
public CaptureByDrawingCache(Activity activity) {
this.activity = activity;
}
@Override
public Bitmap getBitmap() {
View contentView = activity.findViewById(android.R.id.content);
contentView.setDrawingCacheEnabled(true);
return contentView.getDrawingCache();
}
}
emmm…这个代码就更少了!我们来看一下。
- 第一步,同样获取content这个View。
- 第二步,通过View的setDrawingCacheEnabled(true)的方法启用Cache。
- 第三步,通过View的getDrawingCache来获取View缓存的Bitmap。
总结
- 其实实现背景高斯模糊很简单。具体就是两步。
- 第一步,获取要模糊的View,然后获取这个View的截图。
- 第二步,进行高斯模糊。
- 然后就是高斯模糊会用到RenderScript这个我会在后面进行一下介绍。谢谢大家花时间看我的博客!^ ^