1,首先看一下我们今天实现的效果,效果图如下:
2,首先说一下大体的实现思路,首先这个视图一共分为三层,最外层是一个RecyclerView,第二层是一个被虚化的ImageView,第三层是一个正常的ImageView。当用户滑动RecyclerView,监听滑动的高度而动态的改变第二层ImageView的透明度,当RecyclerView滑动高度超过某个特定的高度的时候,透明度达到最大值即第二层虚化的ImageView完全展现。当RecyclerView滑动到起始位置的时候,透明度达到最小值即第二层虚化的ImageView完全隐藏从而展示的是第一层的ImageView。,下面看一下具体的实现步骤:
第一步:了解Renderscript
这是它的官方文档,我们只需要了解它的使用就行了,大致分为一下几个步骤:
① 首先需要通过 Context 创建一个 Renderscript ; ② 其次通过创建的 Renderscript 来创建一个自己需要的脚本( ScriptIntrinsic ),比如这里③ 需要模糊,那就是 ScriptIntrinsicBlur ; ④ 然后至少创建一个 Allocation 类来创建、分配内存空间; ⑤ 接着就是对图像进行一些处理,比如说模糊处理; ⑥ 处理完成后,需要刚才的 Allocation 类来填充分配好的内存空间; ⑦ 最后可以选择性的对一些资源进行回收。
这里我们创建一个BlurBitmapUtil来简单的封装一下,注释很详细,就不废话了,代码如下:
BlurBitmapUtil.java
package com.qianmo.xiaomiblue.utils; import android.content.Context; import android.graphics.Bitmap; import android.os.Build; import android.renderscript.Allocation; import android.renderscript.Element; import android.renderscript.RenderScript; import android.renderscript.ScriptIntrinsicBlur; /** * Created by wangjitao on 2017/3/6 0006. * E-Mail:543441727@qq.com * <p> * 模糊图片工具类 */ public class BlurBitmapUtil { /** * Renderscript 的简单的使用步骤 * 下面简单说一下使用的步骤,这也是官方文档中的说明: * 首先需要通过 Context 创建一个 Renderscript ; * 其次通过创建的 Renderscript 来创建一个自己需要的脚本( ScriptIntrinsic ),比如这里需要模糊,那就是 ScriptIntrinsicBlur ; * 然后至少创建一个 Allocation 类来创建、分配内存空间; * 接着就是对图像进行一些处理,比如说模糊处理; * 处理完成后,需要刚才的 Allocation 类来填充分配好的内存空间; * 最后可以选择性的对一些资源进行回收。 */ //图片等比缩放 private static final float BITMAP_SCALE = 0.4f; /** * 模糊图片工具类 * * @param context * @param image * @param blurRadius * @return */ public static Bitmap blurBitmap(Context context, Bitmap image, float blurRadius) { //设置渲染模糊程度,25f是最大的模糊化度 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { //计算等比缩小的长宽度 int width = Math.round(image.getWidth() * BITMAP_SCALE); int height = Math.round(image.getHeight() * BITMAP_SCALE); //将缩小后的图片作为预渲染的图片 Bitmap inputBitmap = Bitmap.createScaledBitmap(image, width, height, false); //创建一张渲染后的输出图片 Bitmap outputBitmap = Bitmap.createBitmap(inputBitmap); //创建RenderScript内核对象 RenderScript rs = RenderScript.create(context); //创建模糊效果的RenderScript工具对象 ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); //由于RenderScript并没有使用VM分配内存,所以需要使用Allocation来创建和分配内存空间 //创建Allocation对象的时候其实内存使用的,需要使用copyto将数据填充 Allocation allocationInput = Allocation.createFromBitmap(rs, inputBitmap); Allocation allocationOutput = Allocation.createFromBitmap(rs, outputBitmap); blurScript.setRadius(blurRadius); //设置blurscript对象的输入内存 blurScript.setInput(allocationInput); //将输出数据保存到输入内存中 blurScript.forEach(allocationOutput); //将数据填充到allocation中 allocationOutput.copyTo(outputBitmap); return outputBitmap; } else { return null; } } }
第二步:自定义BlurredView,具体实现是实现原ImageView和虚化ImageView的组合,继承自Relativelayout,注释很详细,就直接贴代码了,只要是由setBlurredLevel()方法来控制透明度的改变
自定义的属性:
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="BlurredView"> <attr name="src" format="reference"/> <attr name="disableBlurred" format="boolean"/> </declare-styleable> </resources>
对应的布局文件blurredview.xml
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/blurredview_blurred_img" android:scaleType="fitXY" android:visibility="gone" android:layout_width="match_parent" android:layout_height="match_parent"/> <ImageView android:id="@+id/blurredview_origin_img" android:scaleType="fitXY" android:layout_width="match_parent" android:layout_height="match_parent"/> </FrameLayout>
BlurredView.java
package com.qianmo.xiaomiblue.view; import android.annotation.TargetApi; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.os.Build; import android.util.AttributeSet; import android.view.LayoutInflater; import android.widget.ImageView; import android.widget.RelativeLayout; import com.qianmo.xiaomiblue.R; import com.qianmo.xiaomiblue.utils.BitmapUtil; import com.qianmo.xiaomiblue.utils.BlurBitmapUtil; import static android.R.attr.level; /** * Created by wangjitao on 2017/3/6 0006. * E-Mail:543441727@qq.com */ public class BlurredView extends RelativeLayout { private Context mContext; //最大透明值 private static final int ALPHA_MAX_VALUE = 255; //最大模糊度 private static final float BLUR_RADIUS = 25f; //原图片 private ImageView mOriginalImg; //模糊化后 private ImageView mBlurredImg; private Bitmap mOriginalBitmap; private Bitmap mBlurredBitmap; //是否禁止使用高斯模糊 private boolean isDisableBlurred; public BlurredView(Context context) { super(context); initView(context); } public BlurredView(Context context, AttributeSet attrs) { super(context, attrs); initView(context); initAttr(context, attrs); } public BlurredView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(context); initAttr(context, attrs); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public BlurredView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); initView(context); initAttr(context, attrs); } /** * 当所有子View出现后 设置相关内容 */ @Override protected void onFinishInflate() { super.onFinishInflate(); setImageView(); } /** * 初始化View * * @param context */ private void initView(Context context) { mContext = context; LayoutInflater.from(mContext).inflate(R.layout.blurredview, this); mOriginalImg = (ImageView) findViewById(R.id.blurredview_origin_img); mBlurredImg = (ImageView) findViewById(R.id.blurredview_blurred_img); } /** * 初始化属性 * * @param context * @param attrs */ private void initAttr(Context context, AttributeSet attrs) { TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.BlurredView); Drawable drawable = typedArray.getDrawable(R.styleable.BlurredView_src); isDisableBlurred = typedArray.getBoolean(R.styleable.BlurredView_disableBlurred, false); typedArray.recycle(); //虚化照片 if (null != drawable) { mOriginalBitmap = BitmapUtil.drawableToBitmap(drawable); mBlurredBitmap = BlurBitmapUtil.blurBitmap(context, mOriginalBitmap, BLUR_RADIUS); } //是否可见 if (!isDisableBlurred) { mBlurredImg.setVisibility(VISIBLE); } } /** * 以代码的方式添加待模糊的图片 * * @param blurredBitmap 待模糊的图片 */ public void setBlurredImg(Bitmap blurredBitmap) { if (null != blurredBitmap) { mOriginalBitmap = blurredBitmap; mBlurredBitmap = BlurBitmapUtil.blurBitmap(mContext, blurredBitmap, BLUR_RADIUS); setImageView(); } } /** * 以代码的方式添加待模糊的图片 * * @param blurDrawable 待模糊的图片 */ public void setBlurredImg(Drawable blurDrawable) { if (null != blurDrawable) { mOriginalBitmap = BitmapUtil.drawableToBitmap(blurDrawable); mBlurredBitmap = BlurBitmapUtil.blurBitmap(mContext, mOriginalBitmap, BLUR_RADIUS); setImageView(); } } /** * 填充ImageView */ private void setImageView() { mBlurredImg.setImageBitmap(mBlurredBitmap); mOriginalImg.setImageBitmap(mOriginalBitmap); } /** * 设置模糊程度 * * @param level 模糊程度, 数值在 0~100 之间. */ @SuppressWarnings("deprecation") public void setBlurredLevel(int level) { //超过模糊级别范围 直接抛异常 if (level < 0 || level > 100) { throw new IllegalStateException("No validate level, the value must be 0~100"); } //禁用模糊直接返回 if (isDisableBlurred) { return; } //设置透明度 mOriginalImg.setAlpha((int) (ALPHA_MAX_VALUE - level * 2.55)); } /** * 显示模糊图片 */ public void showBlurredView() { mBlurredImg.setVisibility(VISIBLE); } /** * 选择是否启动/禁止模糊效果 * * @param isDisableBlurred 是否禁用模糊效果 */ @SuppressWarnings("deprecation") public void setBlurredable(boolean isDisableBlurred) { if (isDisableBlurred) { mOriginalImg.setAlpha(ALPHA_MAX_VALUE); mBlurredImg.setVisibility(INVISIBLE); } else { mBlurredImg.setVisibility(VISIBLE); } } /** * 禁用模糊效果 */ @SuppressWarnings("deprecation") public void disableBlurredView() { isDisableBlurred = true; mOriginalImg.setAlpha(ALPHA_MAX_VALUE); mBlurredImg.setVisibility(INVISIBLE); } /** * 启用模糊效果 */ public void enableBlurredView() { isDisableBlurred = false; mBlurredImg.setVisibility(VISIBLE); } }
第三步:设置RecyclerView,并监听滑动,改变虚化图片的透明度
MyAdapter
package com.qianmo.xiaomiblue.adapter; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.qianmo.xiaomiblue.R; /** * Created by Administrator on 2017/3/6 0006. * E-Mail:543441727@qq.com */ public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private Context context; private static final int ITEM_COUNT = 10; private static final int TYPE_HEAD = 0; private static final int TYPE_ITEM = 1; public MyAdapter(Context context) { this.context = context; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == TYPE_HEAD) { return new HeadViewHolder(LayoutInflater.from(context).inflate(R.layout.recyclerview_head, parent, false)); } return new ItemViewHolder(LayoutInflater.from(context).inflate(R.layout.recyclerview_item, parent, false)); } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } @Override public int getItemViewType(int position) { if (position == 0) { return TYPE_HEAD; } else { return TYPE_ITEM; } } @Override public int getItemCount() { return ITEM_COUNT; } public class ItemViewHolder extends RecyclerView.ViewHolder { public ItemViewHolder(View itemView) { super(itemView); } } public class HeadViewHolder extends RecyclerView.ViewHolder { public HeadViewHolder(View itemView) { super(itemView); } } }
在MainActivity中设置
recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setAdapter(new MyAdapter(this)); recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); mScrollerY += dy; //根据滚动距离控制模糊程度 滚动距离是模糊程度的十倍 if (Math.abs(mScrollerY) > 1000) { mAlpha = 100; } else { mAlpha = Math.abs(mScrollerY) / 10; } //设置透明度等级 blurredView.setBlurredLevel(mAlpha); } });
ok,这样我们的功能就实现了 ,很简单有没有,主要是Rederscript的掌握
github项目地址