关于在Android开发中使用模糊透明效果的方法

来源:互联网 发布:java 泛型类 静态方法 编辑:程序博客网 时间:2024/06/13 22:53

模糊透明效果这几年在UI开发中非常常见,最初是Windows在Vista中使用在开始菜单、标题栏和边框上,随后其它的操作系统都纷纷跟进,像Ubuntu等在随后的版本中大量的使用,但在手机上使用也不过是近两三年的事,毕竟手机上有个性能的问题在里面。所谓模糊透明都是通过CPU的运算即时生成的,这其中透明效果还算好处理,很久以前XP就已经使用了这种特效,相比模糊处理要简单许多。而模糊效果需要占用到大量的CPU资源进行计算,如果要对1000个像素进行计算的话,可不是仅仅循环1000次那么简单。因为每一个像素都需要计算出此像素与周围像素之间的平均值,而随着模糊半径的增大计算量也成倍的增大。而手机的CPU速度毕竟不是台式机可比拟的,而且大量的运算对移动设备来说也是非常耗电的,这是Windows在笔记本上默认是关闭此功能的原因。不过既然客户有要求,作为开发人员的我们还是要尽量去满足。来了能实现模糊透明效果我特意写了一个工具类。

/** * 快速模糊 *  * @param sentBitmap * @param radius * @return */public static Bitmap fastBlur(Bitmap sentBitmap, int radius) {// Stack Blur v1.0 from// http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html//// Java Author: Mario Klingemann <mario at quasimondo.com>// http://incubator.quasimondo.com// created Feburary 29, 2004// Android port : Yahel Bouaziz <yahel at kayenko.com>// http://www.kayenko.com// ported april 5th, 2012// This is a compromise between Gaussian Blur and Box blur// It creates much better looking blurs than Box Blur, but is// 7x faster than my Gaussian Blur implementation.//// I called it Stack Blur because this describes best how this// filter works internally: it creates a kind of moving stack// of colors whilst scanning through the image. Thereby it// just has to add one new block of color to the right side// of the stack and remove the leftmost color. The remaining// colors on the topmost layer of the stack are either added on// or reduced by one, depending on if they are on the right or// on the left side of the stack.//// If you are using this algorithm in your code please add// the following line://// Stack Blur Algorithm by Mario Klingemann <mario@quasimondo.com>Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);if (radius < 1) {return (null);}int w = bitmap.getWidth();int h = bitmap.getHeight();int[] pix = new int[w * h];bitmap.getPixels(pix, 0, w, 0, 0, w, h);int wm = w - 1;int hm = h - 1;int wh = w * h;int div = radius + radius + 1;int r[] = new int[wh];int g[] = new int[wh];int b[] = new int[wh];int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;int vmin[] = new int[Math.max(w, h)];int divsum = (div + 1) >> 1;divsum *= divsum;int dv[] = new int[256 * divsum];for (i = 0; i < 256 * divsum; i++) {dv[i] = (i / divsum);}yw = yi = 0;int[][] stack = new int[div][3];int stackpointer;int stackstart;int[] sir;int rbs;int r1 = radius + 1;int routsum, goutsum, boutsum;int rinsum, ginsum, binsum;for (y = 0; y < h; y++) {rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;for (i = -radius; i <= radius; i++) {p = pix[yi + Math.min(wm, Math.max(i, 0))];sir = stack[i + radius];sir[0] = (p & 0xff0000) >> 16;sir[1] = (p & 0x00ff00) >> 8;sir[2] = (p & 0x0000ff);rbs = r1 - Math.abs(i);rsum += sir[0] * rbs;gsum += sir[1] * rbs;bsum += sir[2] * rbs;if (i > 0) {rinsum += sir[0];ginsum += sir[1];binsum += sir[2];} else {routsum += sir[0];goutsum += sir[1];boutsum += sir[2];}}stackpointer = radius;for (x = 0; x < w; x++) {r[yi] = dv[rsum];g[yi] = dv[gsum];b[yi] = dv[bsum];rsum -= routsum;gsum -= goutsum;bsum -= boutsum;stackstart = stackpointer - radius + div;sir = stack[stackstart % div];routsum -= sir[0];goutsum -= sir[1];boutsum -= sir[2];if (y == 0) {vmin[x] = Math.min(x + radius + 1, wm);}p = pix[yw + vmin[x]];sir[0] = (p & 0xff0000) >> 16;sir[1] = (p & 0x00ff00) >> 8;sir[2] = (p & 0x0000ff);rinsum += sir[0];ginsum += sir[1];binsum += sir[2];rsum += rinsum;gsum += ginsum;bsum += binsum;stackpointer = (stackpointer + 1) % div;sir = stack[(stackpointer) % div];routsum += sir[0];goutsum += sir[1];boutsum += sir[2];rinsum -= sir[0];ginsum -= sir[1];binsum -= sir[2];yi++;}yw += w;}for (x = 0; x < w; x++) {rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;yp = -radius * w;for (i = -radius; i <= radius; i++) {yi = Math.max(0, yp) + x;sir = stack[i + radius];sir[0] = r[yi];sir[1] = g[yi];sir[2] = b[yi];rbs = r1 - Math.abs(i);rsum += r[yi] * rbs;gsum += g[yi] * rbs;bsum += b[yi] * rbs;if (i > 0) {rinsum += sir[0];ginsum += sir[1];binsum += sir[2];} else {routsum += sir[0];goutsum += sir[1];boutsum += sir[2];}if (i < hm) {yp += w;}}yi = x;stackpointer = radius;for (y = 0; y < h; y++) {// Preserve alpha channel: ( 0xff000000 & pix[yi] )pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum];rsum -= routsum;gsum -= goutsum;bsum -= boutsum;stackstart = stackpointer - radius + div;sir = stack[stackstart % div];routsum -= sir[0];goutsum -= sir[1];boutsum -= sir[2];if (x == 0) {vmin[y] = Math.min(y + r1, hm) * w;}p = x + vmin[y];sir[0] = r[p];sir[1] = g[p];sir[2] = b[p];rinsum += sir[0];ginsum += sir[1];binsum += sir[2];rsum += rinsum;gsum += ginsum;bsum += binsum;stackpointer = (stackpointer + 1) % div;sir = stack[stackpointer];routsum += sir[0];goutsum += sir[1];boutsum += sir[2];rinsum -= sir[0];ginsum -= sir[1];binsum -= sir[2];yi += w;}}bitmap.setPixels(pix, 0, w, 0, 0, w, h);return (bitmap);}@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)public static Bitmap fastblur16(Bitmap source, int radius, Context ctx) {Bitmap bitmap = source.copy(source.getConfig(), true);RenderScript rs = RenderScript.create(ctx);Allocation input = Allocation.createFromBitmap(rs, source, Allocation.MipmapControl.MIPMAP_NONE,Allocation.USAGE_SCRIPT);Allocation output = Allocation.createTyped(rs, input.getType());ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));script.setRadius(radius);script.setInput(input);script.forEach(output);output.copyTo(bitmap);return bitmap;}/** * 对View控件的背景进行模糊处理 *  * 模糊效果会大量占用CPU资源,不推荐使用在动态界面中,会非常耗电 *  * @param context * @param bkg * @param view * @param radius模糊的半径 * @param scaleFactory缩放因子主要是为了优化算法加快速度 * @param marginLeft * @param marginTop */@SuppressLint("NewApi")public static void blurViewBg(Context context, Bitmap bkg, View view, int radius, float scaleFactor,int marginLeft, int marginTop) {// 参数的有效性判断radius = radius < 0 || radius > 25 ? 2 : radius;scaleFactor = scaleFactor <= 0 ? 1 : scaleFactor;// 数据单位转换marginLeft = (int) (ScreenUtils.dp2Px(context, marginLeft));marginTop = (int) (ScreenUtils.dp2Px(context, marginTop));// 根据缩放因子创建一个相应比例的位图,从背景位图中截取相应位置的画面到此Bitmap overlay = Bitmap.createBitmap((int) ((view.getMeasuredWidth()) / scaleFactor),(int) ((view.getMeasuredHeight()) / scaleFactor), Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(overlay);canvas.translate((-view.getLeft() - marginLeft) / scaleFactor, (-view.getTop() - marginTop) / scaleFactor);canvas.scale(1 / scaleFactor, 1 / scaleFactor);Paint paint = new Paint();paint.setFlags(Paint.FILTER_BITMAP_FLAG);canvas.drawBitmap(bkg, 0, 0, paint);// 将创建的位图做模糊处理并做为参数view的背景overlay = BitmapUtils.fastBlur(overlay, (int) radius);view.setBackground(new BitmapDrawable(context.getResources(), overlay));}
<span style="white-space:pre"></span>/**<span style="white-space:pre"></span> * 截取可见屏幕部分的view视图<span style="white-space:pre"></span> */<span style="white-space:pre"></span>public static Bitmap shotViewBitmap(View v) {<span style="white-space:pre"></span>v.clearFocus();<span style="white-space:pre"></span>v.setPressed(false);<span style="white-space:pre"></span>Bitmap bmp = null;<span style="white-space:pre"></span>try {<span style="white-space:pre"></span>// 允许当前窗口保存缓存信息,这样getDrawingCache()方法才会返回一个Bitmap<span style="white-space:pre"></span>v.setDrawingCacheEnabled(true);<span style="white-space:pre"></span>v.buildDrawingCache();<span style="white-space:pre"></span>bmp = Bitmap.createBitmap(v.getDrawingCache());<span style="white-space:pre"></span>} catch (Exception e) {<span style="white-space:pre"></span>e.printStackTrace();<span style="white-space:pre"></span>}<span style="white-space:pre"></span>return bmp;<span style="white-space:pre"></span>}
上面的三个方法都不是我自己写的,是从网上找到后略微修改了下。

fastBlur传入的是一个需要被模糊化的位图,参数radius就是模糊半径,半径不能大于25,返回值已经模糊化后的位置。

fastblur16方法的效果和fastBlur相同,只是使用一个API16才开始有的一些方法,但处理后的模糊效果都是一样的。

blurViewBg方法就用来实现模糊透明的,参数view指出需要对这种效果的控件,bkg指出需要被作为模糊透明的位图,radius为模糊半径,scaleFactor是缩小因子,这个参数是种优化算法,主要是将位图按倍数缩小以减少像素加快计算速度的。如果view控件有marginTop和marginLeft的话也要作为参数传入。

shotViewBitmap方法是对控件进行截图并保存为Bitmap对象。我们需要制作模糊透明效果的话必然是在一个控件后面还要有一个为背景的控件,此方法就是对这个背景控件进行截图并将返回的Bitmap作为参数传给blurViewBg方法。注意如果是把一个布局对象传给此方法的话是会报错的。


好了!下面给出如果调用这些工具类的方法演示

package com.androidcustomlibrarydemo.fragment;import android.graphics.Bitmap;import android.os.Bundle;import android.support.v4.app.Fragment;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.view.ViewTreeObserver.OnPreDrawListener;import android.widget.ImageView;import android.widget.ListView;import android.widget.TextView;import com.android.common.utils.BitmapUtils;import com.androidcustomlibrarydemo.R;import com.androidcustomlibrarydemo.adapter.ItemAdapter;public class BlurViewFragment extends Fragment {private View view;private ListView listView;private ImageView imgView;private TextView tvBottom;private Bitmap bg;public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {view = inflater.inflate(R.layout.fragment_blur, container, false);initViewController();return view;}private void initViewController() {imgView = (ImageView) view.findViewById(R.id.img_view);listView = (ListView) view.findViewById(R.id.listView1);tvBottom = (TextView) view.findViewById(R.id.textView1);tvBottom.setText("模糊化处理是一种非常耗资源的处理,对于电量和CPU的使用率较高,因此不建议在界面中大量的使用,尤其是在列表项的背景中动态的模糊会出现界面卡顿现象,此界面已做了一定的优化");// 因为需要获取ImageView里的图像所以在此调用控件的观察者,并添加监听器以便于当控件加载完毕做相应的处理imgView.getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() {@Overridepublic boolean onPreDraw() {if (bg == null) {// 首先对ImageView进行截图并保存为位图bg = BitmapUtils.shotViewBitmap(imgView);// 对底部的TextView的背景进行模糊化处理// 参数中的2代表模糊半径,4代表缩小因子BitmapUtils.blurViewBg(getActivity(), bg, tvBottom, 2, 4, 0, 0);// 对背景图片进行模糊,并将背景图片传给列表的适配器bg = BitmapUtils.fastBlur(bg, 10);listView.setAdapter(new ItemAdapter(BlurViewFragment.this.getActivity(), bg));// 移除ImageView的观察器,如果不移除的话控件会在每次重绘时频繁的回调onPreDraw方法imgView.getViewTreeObserver().removeOnPreDrawListener(this);}return true;}});}}
fragment_blur.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/RelativeLayout1"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="com.example.blurdemo.MainActivity" >    <ImageView        android:id="@+id/img_view"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:layout_alignParentLeft="true"        android:layout_alignParentTop="true"        android:scaleType="fitXY"        android:src="@drawable/act_bg" />    <TextView        android:id="@+id/textView1"        android:layout_width="match_parent"        android:layout_height="100dp"        android:layout_alignParentBottom="true"        android:layout_alignParentLeft="true"        android:padding="10dp"        android:text="TextView"        android:textColor="#fff" />    <LinearLayout        android:id="@+id/LinearLayout1"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_above="@+id/textView1"        android:layout_alignParentLeft="true"        android:layout_alignParentTop="true"        android:orientation="horizontal" >        <View            android:layout_width="50dp"            android:layout_height="match_parent" />        <ListView            android:id="@+id/listView1"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_margin="10dp"            android:layout_weight="1"            android:background="@null"            android:dividerHeight="10dp" >        </ListView>        <View            android:layout_width="50dp"            android:layout_height="match_parent" />    </LinearLayout></RelativeLayout>
ItemAdapter.java

package com.androidcustomlibrarydemo.adapter;import com.android.common.utils.BitmapUtils;import com.android.common.utils.ScreenUtils;import com.androidcustomlibrarydemo.R;import android.annotation.SuppressLint;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.drawable.BitmapDrawable;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.view.ViewTreeObserver.OnPreDrawListener;import android.widget.BaseAdapter;public class ItemAdapter extends BaseAdapter {private Context context;private Bitmap bg;public ItemAdapter(Context context, Bitmap bg) {this.context = context;this.bg = bg;}@Overridepublic int getCount() {return 110;}@Overridepublic Object getItem(int position) {// TODO Auto-generated method stubreturn null;}@Overridepublic long getItemId(int position) {// TODO Auto-generated method stubreturn position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {if (convertView == null) {convertView = LayoutInflater.from(context).inflate(R.layout.list_item_blur, null);final View view = convertView;view.getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() {@Overridepublic boolean onPreDraw() {// 不建议在列表的适配器中调用blurViewBg方法,因为无论在性能还是在界面效果上都不理想// 因此参数bg是直接处理已经模糊好的背景位图,在此只是根据列表的每一项的位置坐标进行截取显示showViewBg(bg, view, 0, 10, 10, 50, 0);// 在列表的适配中不能移除观察者的监听return true;}});}return convertView;}@SuppressLint("NewApi")public void showViewBg(Bitmap bkg, View view, int radius, int marginLeft, int marginTop, int offx, int offy) {radius = radius < 0 || radius > 25 ? 2 : radius;marginLeft = (int) (ScreenUtils.dp2Px(context, marginLeft));marginTop = (int) (ScreenUtils.dp2Px(context, marginTop));offx = (int) ScreenUtils.dp2Px(context, offx);offy = (int) ScreenUtils.dp2Px(context, offy);Bitmap overlay = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(), Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(overlay);canvas.translate((-view.getLeft() - marginLeft - offx), (-view.getTop() - marginTop - offy));Paint paint = new Paint();paint.setFlags(Paint.FILTER_BITMAP_FLAG);canvas.drawBitmap(bkg, 0, 0, paint);view.setBackground(new BitmapDrawable(context.getResources(), overlay));}}
list_item_blur.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:gravity="center_vertical"    android:orientation="horizontal" >    <ImageView        android:id="@+id/imageView1"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:src="@drawable/ic_launcher" />    <TextView        android:id="@+id/textView1"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="TextView"        android:textColor="#fff" /></LinearLayout>

最后看一下效果图




0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 云集微店的商品没货了怎么办 淘宝买家被检测有虚拟交易怎么办 媒体声音突然没有声音了该怎么办 华为微信运动步数为零怎么办 淘宝店铺没货了客户拍了怎么办 房子涨价了卖家反悔不卖了怎么办 买的东西很贵质量不好怎么办 在淘宝开的店账号忘了怎么办 建了个淘宝优惠券群没人购物怎么办 刚开的淘宝店没有生意怎么办 房产代理公司不给渠道结佣金怎么办 天猫超过72小时不发货怎么办 流量魔盒苹果下载怎么打不开怎么办 淘宝包邮店铺新疆地区拍怎么办 淘宝客服当顾客要优惠时怎么办 微信手机号注册的找不到了怎么办 之前注册的微信找不到了怎么办 苹果ipad的id密码忘了怎么办 淘宝和支付宝用一张银行卡怎么办 淘宝卖家填写虚假物流信息怎么办 淘宝店铺的浏览量越来越少怎么办 网上充手机话费充错了怎么办 夜神模拟器上陌陌的位置不对怎么办 如果在大庭广众之下放了个屁怎么办 淘宝分销上传宝贝被系统下架怎么办 酷狗喜欢歌单里面的歌都没了怎么办 苹果手机下载不了微信缓冲怎么办 登陆微信提示版本过低登不了怎么办 苹果手机微信版本过低登不上怎么办 微信小程序显示微信版本过低怎么办 三星手机登微信显示版本过低怎么办 微信版本低无法登录无法升级怎么办 手机淘宝五应用界面无法打开怎么办 入住淘宝主播没有微博粉丝怎么办 手机淘宝领金币怎么没有了怎么办 淘宝荬家缺货对付款买家怎么办 淘宝买家确认收货后申请退款怎么办 淘宝东西失效了但付过款了怎么办 淘宝图片被投诉盗图怎么办原图没了 淘宝退款申请不小心撤销了怎么办 淘宝不小心点了撤销退款怎么办