Android自定义View之仿IOS模糊控件 (标题栏滑动过程
2020-06-20 本文已影响0人
请叫我果爸
前言
Android开发过程中,总是需要与IOS坐比较,每次产品经理都要问,为什么IOS能做到,Android做不到。并不是Android做不到,主要原因是IOS下,有些控件是有现成的组件库的,Android没有,所以Android需要去自己绘制。
上次产品经理就让我写一个功能,需要在页面滑动时,顶部导航栏需要从透明到模糊渐变,一定程度后不再改变。查阅了网上各种资料,发现关于Android高斯模糊的确有很多文章,但他们都是对于一个静态的页面或者图片做模糊,使用RenderScript高效计算平台进行模糊就好了。但我需要的效果中,页面是动态的,底下View是一直在改变的,怎么让他在需要的区域模糊呢。
废话不多说,先看实现效果,点击看视频效果,更加清晰流畅。
上面的效果是大家想要的吗?
实现方式
其实我的思路很简单,就只有四步,获取位置-裁剪-转化-模糊
Step 1 通过onLayout方法,先获取目标区域的位置
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
// Log.i("BlurView", "onLayoutBlurView changed=" + changed + " left=" + left + " ,top=" + top + " ,right=" + right + " ,bottom=" + bottom);
lastActionTime = System.currentTimeMillis();
//获取Bitmap从View
setBlurBitmapFromView(getLeft(), getTop(), getRight(), getBottom());
}
Step 2 在整个Windows窗口中,对目标区域的View进行裁剪
/**
* 获取需要Bitmap
* @param left
* @param top
* @param right
* @param bottom
*/
private void setBlurBitmapFromView(int left, int top, int right, int bottom) {
//获取父View
ViewGroup parent = (ViewGroup) getParent();
//将此布局从父View移除,在截图不截进此视图。
parent.removeView(this);
//获取对应位置的Bitmap对象
bitmap = getDownscaledBitmapForView(parent, new Rect(left, top, right, bottom), downScaleFactor);
//截完图获取到bitmap之后,再把此View加载到父布局上
parent.addView(this);
printfActionTime("图片处理");
//模糊处理
bitmap = blurBitmap(bitmap, mBlurRadius);
printfActionTime("模糊处理");
}
Step 3 然后把裁剪下来的View转化成Bitmap,此时先做一次Bitmap压缩,为了让RenderScript计算的更快
/**
* 裁剪View,View转Bitmap,同时进行Bitmap压缩
* @param view
* @param crop
* @param downscaleFactor 压缩比例
* @return
*/
private Bitmap getDownscaledBitmapForView(View view, Rect crop, float downscaleFactor) {
int width = Math.round(crop.width() * downscaleFactor);
int height = Math.round(crop.height() * downscaleFactor);
if (view.getWidth() <= 0 || view.getHeight() <= 0 || width <= 0 || height <= 0) {
throw new IllegalArgumentException("No screen available (width or height = 0)");
}
float dx = -crop.left * downscaleFactor;
float dy = -crop.top * downscaleFactor;
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Matrix matrix = new Matrix();
matrix.preScale(downscaleFactor, downscaleFactor);
matrix.postTranslate(dx, dy);
canvas.setMatrix(matrix);
view.draw(canvas);
return bitmap;
}
Step 4 最后再进行模糊处理就好了
/**
* 模糊处理
* @param image
* @param blurRadius
* @return
*/
public Bitmap blurBitmap(Bitmap image, float blurRadius) {
// 创建一张渲染后的输出图片
Bitmap outputBitmap = Bitmap.createBitmap(image);
// Log.i("BlurView", "onLayoutBlurView bitmap.size=" + inputBitmap.getByteCount());
// 由于RenderScript并没有使用VM来分配内存,所以需要使用Allocation类来创建和分配内存空间
// 创建Allocation对象的时候其实内存是空的,需要使用copyTo()将数据填充进去
Allocation tmpIn = Allocation.createFromBitmap(rs, image);
Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap);
// 设置渲染的模糊程度, 25f是最大模糊度
blurScript.setRadius(blurRadius);
// 设置blurScript对象的输入内存
blurScript.setInput(tmpIn);
// 将输出数据保存到输出内存中
blurScript.forEach(tmpOut);
// 将数据填充到Allocation中
tmpOut.copyTo(outputBitmap);
image.recycle();
rs.destroy();
return outputBitmap;
}
思路其实很简单的,代码也非常简洁,需要在复杂一点的,可以自己去扩展。
自取
源码地址:BlurView
Github地址:Open-View
有帮助就帮忙点个赞吧~