实现简单的高斯模糊效果
此文章参考了大神的博客:教你一分钟实现动态模糊效果_android动态模糊-优快云博客。
先上效果图:
首先,我们新建一个android空项目,命名为:BlurbackGround
既然是模糊背景,首先肯定就需要一张背景图,所以我们在网上随便找一张背景图下载下来,然后复制到drawable文件夹下,图片命名为:bg_blur.jpg
接下来在values文件夹下添加一个attr.xml文件,用来保存一些基本的属性值
attr.xml的文件内容:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="BlurredView">
<attr name="src" format="reference"/>
<attr name="move" format="boolean"/>
<attr name="disableBlurred" format="boolean"/>
</declare-styleable>
</resources>
添加完成之后,再添加一个screens.xml文件,用来存储默认的屏幕边距
screens.xml的文件内容:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 默认的屏幕边距-->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="half_margin">8dp</dimen>
<dimen name="small_margin">4dp</dimen>
<dimen name="thumb_size">80dp</dimen>
</resources>
完成之后,在layout文件夹下添加一个帧布局文件blurredview.xml
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>
基础工作已做好,接下来在MainActivity同级位置创建一个文件夹命名为:blurview
在blurview文件夹下创建三个类,分别为:BlurBitmap、BlurredUtil、BlurredView
BlurBitmap的文件内容:
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;
import android.support.annotation.RequiresApi;
public class BlurBitmap {
/**
* 图片缩放比例
*/
private static final float BITMAP_SCALE = 0.4f;
/**
* 最大模糊度(在0.0到25.0之间)
*/
private static final float BLUR_RADIUS = 25f;
/**
* 模糊图片的具体方法
*
* @param context 上下文对象
* @param image 需要模糊的图片
* @return 模糊处理后的图片
*/
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
static Bitmap blur(Context context, Bitmap image) {
// 计算图片缩小后的长宽
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 tmpIn = Allocation.createFromBitmap(rs, inputBitmap);
Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap);
// 设置渲染的模糊程度, 25f是最大模糊度
blurScript.setRadius(BLUR_RADIUS);
// 设置blurScript对象的输入内存
blurScript.setInput(tmpIn);
// 将输出数据保存到输出内存中
blurScript.forEach(tmpOut);
// 将数据填充到Allocation中
tmpOut.copyTo(outputBitmap);
return outputBitmap;
}
}
BlurredUtil的文件内容:
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
public class BlurredUtil {
/**
* 将Drawable对象转化为Bitmap对象
*
* @param drawable Drawable对象
* @return 对应的Bitmap对象
*/
static Bitmap drawableToBitmap(Drawable drawable) {
Bitmap bitmap;
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
if (bitmapDrawable.getBitmap() != null) {
return bitmapDrawable.getBitmap();
}
}
if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
bitmap = Bitmap.createBitmap(1, 1,
Bitmap.Config.ARGB_8888); // Single color bitmap will be created of 1x1 pixel
} else {
bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(),
Bitmap.Config.ARGB_8888);
}
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
}
BlurredView的文件内容:
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import com.example.administrator.blurbackground.R;
public class BlurredView extends RelativeLayout {
/**
* 模糊最大化值
*/
private static final int ALPHA_MAX_VALUE = 255;
/**
* Context
*/
private Context mContext;
/**
* 模糊后的ImageView
*/
private ImageView mBlurredImg;
/**
* 原图ImageView
*/
private ImageView mOriginImg;
/**
* 原图Bitmap
*/
private Bitmap mOriginBitmap;
/**
* 模糊后的Bitmap
*/
private Bitmap mBlurredBitmap;
/**
* 是否禁用模糊效果
*/
private boolean isDisableBlurred;
/**
* 是否移动背景图片
*/
private boolean isMove;
public BlurredView(Context context) {
super(context);
init(context);
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
public BlurredView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
initAttr(context, attrs);
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
public BlurredView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
initAttr(context, attrs);
}
private void init(Context context) {
mContext = context;
LayoutInflater.from(context).inflate(R.layout.blurredview, this);
mOriginImg = (ImageView) findViewById(R.id.blurredview_origin_img);
mBlurredImg = (ImageView) findViewById(R.id.blurredview_blurred_img);
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
private void initAttr(Context context, AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.BlurredView);
Drawable drawable = typedArray.getDrawable(R.styleable.BlurredView_src);
isMove = typedArray.getBoolean(R.styleable.BlurredView_move, false);
isDisableBlurred = typedArray.getBoolean(R.styleable.BlurredView_disableBlurred, false);
typedArray.recycle();
// blur image
if (null != drawable) {
mOriginBitmap = BlurredUtil.drawableToBitmap(drawable);
mBlurredBitmap = BlurBitmap.blur(context, mOriginBitmap);
}
// setVisibility
if (!isDisableBlurred) {
mBlurredImg.setVisibility(VISIBLE);
}
// setMove
if (null != drawable) {
setMove(context, isMove);
}
}
/**
* 设置背景图片移动效果
* @param context 上下文对象
* @param isMove 是否移动
*/
private void setMove(Context context, boolean isMove) {
if (isMove) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point point = new Point();
display.getSize(point);
int height = point.y;
setBlurredHeight(height, mOriginImg);
setBlurredHeight(height, mBlurredImg);
}
}
/**
* 改变图片的高度
*
* @param height 图片的高度
* @param imageView imageview对象
*/
private void setBlurredHeight(int height, ImageView imageView) {
ViewGroup.LayoutParams params = imageView.getLayoutParams();
params.width = ViewGroup.LayoutParams.MATCH_PARENT;
params.height = height + 100;
imageView.requestLayout();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
setImageView();
}
/**
* 填充ImageView.
*/
private void setImageView() {
mBlurredImg.setImageBitmap(mBlurredBitmap);
mOriginImg.setImageBitmap(mOriginBitmap);
}
/**
* 以代码的方式添加待模糊的图片
*
* @param blurredBitmap 待模糊的图片
*/
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
public void setBlurredImg(Bitmap blurredBitmap) {
if (null != blurredBitmap) {
mOriginBitmap = blurredBitmap;
mBlurredBitmap = BlurBitmap.blur(mContext, blurredBitmap);
setImageView();
setMove(mContext, isMove);
}
}
/**
* 以代码的方式添加待模糊的图片
*
* @param blurDrawable 待模糊的图片
*/
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
public void setBlurredImg(Drawable blurDrawable) {
if (null != blurDrawable) {
mOriginBitmap = BlurredUtil.drawableToBitmap(blurDrawable);
mBlurredBitmap = BlurBitmap.blur(mContext, mOriginBitmap);
setImageView();
setMove(mContext, isMove);
}
}
/**
* 设置模糊程度
*
* @param level 模糊程度, 数值在 0~100 之间.
*/
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;
}
mOriginImg.setAlpha((int) (ALPHA_MAX_VALUE - level * 2.55));
}
/**
* 设置图片上移的距离
*
* @param hight 向上移动的距离
*/
public void setBlurredTop(int hight) {
mOriginImg.setTop(-hight);
mBlurredImg.setTop(-hight);
}
/**
* 显示模糊图片
*/
public void showBlurredView() {
mBlurredImg.setVisibility(VISIBLE);
}
/**
* 禁用模糊效果
*/
public void disableBlurredView() {
isDisableBlurred = true;
mOriginImg.setAlpha(ALPHA_MAX_VALUE);
mBlurredImg.setVisibility(INVISIBLE);
}
/**
* 启用模糊效果
*/
public void enableBlurredView() {
isDisableBlurred = false;
mBlurredImg.setVisibility(VISIBLE);
}
}
好了,现在我们来写一下activity_main.xml的布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.administrator.blurbackground.blurview.BlurredView
android:id="@+id/activity_main_blurredview"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="0dp"/>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="80dp">
<SeekBar
android:layout_marginTop="@dimen/activity_vertical_margin"
android:id="@+id/activity_main_seekbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"/>
<TextView
android:id="@+id/activity_main_progress_tv"
android:text="0"
android:textSize="24sp"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
如果页面呈现这个样子:说明引用BlurredView的路径有问题,手输
这个样子就可以了。
附上activity_main.xml代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.administrator.blurbackground.blurview.BlurredView
android:id="@+id/activity_main_blurredview"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="0dp"/>
</LinearLayout>
接下来就是MainActivity啦,也是最后一步
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.SeekBar;
import android.widget.TextView;
import com.example.administrator.blurbackground.blurview.BlurredView;
public class MainActivity extends AppCompatActivity {
/**
* Blurredview
*/
private BlurredView mBlurredView;
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBlurredView = (BlurredView) findViewById(R.id.activity_main_blurredview);
// 可以在代码中使用setBlurredImg()方法指定需要模糊的图片
mBlurredView.setBlurredImg(getResources().getDrawable(R.drawable.bg_blur));
mBlurredView.setBlurredLevel(80);
}
}
最重要的就是这几句
mBlurredView = (BlurredView) findViewById(R.id.activity_main_blurredview);(这是找到BlurredView)
mBlurredView.setBlurredImg(getResources().getDrawable(R.drawable.bg_blur));(这是指定需要模糊的图片)
mBlurredView.setBlurredLevel(80);(80是模糊度,setBlurredLevel的范围为0-100,数值越大越模糊)
到这里一个简单的android的背景模糊功能就基本实现了,大功告成。
我自己也是初学者,还有很多地方不懂,上述文章如有错误,欢迎大家指正,谢谢!
附上demo链接:https://download.youkuaiyun.com/download/qq_37181771/10781968