您好,登錄后才能下訂單哦!
今天就跟大家聊聊有關如何在Android中使用RenderScript實現一個毛玻璃模糊效果,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。
RenderScript 介紹
在開始之前,先看下 RenderScript 的官方介紹:
RenderScript is a framework for running computationally intensive tasks at high performance on Android. RenderScript is primarily oriented for use with data-parallel computation, although serial workloads can benefit as well. The RenderScript runtime parallelizes work across processors available on a device, such as multi-core CPUs and GPUs. This allows you to focus on expressing algorithms rather than scheduling work. RenderScript is especially useful for applications performing image processing, computational photography, or computer vision.
大致意思就是說 RenderScript 是 Android 平臺上為了計算密集型任務的一中高性能框架,并且RenderScript 尤其對圖像的處理特別有用。另外,RenderScript 之所以效率高是因為其底層是 C 實現的。
使用 RenderScript Support Library
為了可以兼容到更早的版本,我們直接使用 android.support.v8.renderscript
(支持API level 9+)包下的,而不使用android.renderscript(支持API level 11+)
以 Android Studio 為例,打開你的 app 的 build.gradle 文件,在 android 的 defaultConfig 結點添加兩句:
renderscriptTargetApi 18 renderscriptSupportModeEnabled true
其中 renderscriptTargetApi 的值官方說的是從 11 到最新的 API Level 都可以
這樣我們等下導包就可以導 v8 內的了。
模糊背景
局部模糊
先上一張我們要實現的效果圖:
這里可以看到實現的是局部模糊,在圖片的正中間有一個 TextView,TextView 的背景部分做了模糊處理。
先大致說下模糊的主要步驟(完全模糊步驟一樣):
首先取出 TextView 在 ImageView 正上方處的那一塊背景
然后對取出的那一塊背景做模糊處理
最后把模糊處理后的背景再設為 TextView 的背景
這樣,就可以達到我們圖片中的局部模糊效果,具體的過程在代碼中有詳細的注釋。
下面先貼上布局文件:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="20dp"> <FrameLayout android:layout_width="300dp" android:layout_height="300dp" android:layout_centerInParent="true"> <ImageView android:id="@+id/image" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" android:src="@drawable/img"/> <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:text="Melody" android:textColor="@android:color/white" android:textSize="45sp"/> </FrameLayout> </RelativeLayout>
再貼上java代碼:
public class MainActivity extends Activity implements Runnable { private static final String TAG = "MainActivity"; private ImageView mImage; private TextView mText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mImage = (ImageView) findViewById(R.id.image); mText = (TextView) findViewById(R.id.text); // onCreate()內無法到ImageView的背景,所以需要 post 到消息隊列內稍后執行 mImage.post(this); } @Override public void run() { blur(getImageViewBitmap(mImage), mText); } /** * 取出一個imageView的bitmap背景 */ public Bitmap getImageViewBitmap(ImageView imageView) { imageView.setDrawingCacheEnabled(true); // 取出ImageView的Bitmap Bitmap bitmap = imageView.getDrawingCache(); // 拷貝一份bitmap用作模糊 Bitmap bitmapCopy = bitmap.copy(bitmap.getConfig(), true); imageView.setDrawingCacheEnabled(false); return bitmapCopy; } /** * 模糊的具體實現 * * @param inputBitmap 要模糊的 bitmap * @param targetView 需要被模糊背景的 View */ public void blur(Bitmap inputBitmap, View targetView) { // 創建一個和目標View(需要背景被模糊的View)寬高一樣的空的 outputBitmap Bitmap outputBitmap = Bitmap.createBitmap((int) (targetView.getMeasuredWidth()), (int) (targetView.getMeasuredHeight()), Bitmap.Config.ARGB_8888); // 將 outputBitmap 關聯在 canvas 上 Canvas canvas = new Canvas(outputBitmap); // 畫布移動到目標 View 在父布局中的位置 canvas.translate(-targetView.getLeft(), -targetView.getTop()); Paint paint = new Paint(); paint.setFlags(Paint.FILTER_BITMAP_FLAG); // 將要模糊的 inputBitmap 繪制到 outputBitmap 上 // 因為剛才做了 translate 操作,這樣就可以裁剪到目標 View 在父布局內的那一塊背景到 outputBitmap 上 canvas.drawBitmap(inputBitmap, 0, 0, paint); // ----接下來做模糊 outputBitmap 處理操作---- // 創建 RenderScript RenderScript rs = RenderScript.create(this); Allocation input = Allocation.createFromBitmap(rs, outputBitmap); Allocation output = Allocation.createTyped(rs, input.getType()); // 使用 ScriptIntrinsicBlur 類來模糊圖片 ScriptIntrinsicBlur blur = ScriptIntrinsicBlur.create( rs, Element.U8_4(rs)); // 設置模糊半徑 ( 取值范圍為( 0.0f , 25f ] ,半徑越大,模糊效果也越大) blur.setRadius(25f); blur.setInput(input); // 模糊計算 blur.forEach(output); // 模糊 outputBitmap output.copyTo(outputBitmap); // 將模糊后的 outputBitmap 設為目標 View 的背景 targetView.setBackground(new BitmapDrawable(getResources(), outputBitmap)); rs.destroy(); } }
導的是 v8 的包:
import android.support.v8.renderscript.Allocation; import android.support.v8.renderscript.Element; import android.support.v8.renderscript.RenderScript; import android.support.v8.renderscript.ScriptIntrinsicBlur;
完全模糊
上面是局部模糊,然后我們改變一下 TextView 的寬高鋪滿父布局,使其和 ImageView 大小一樣來實現完全模糊效果:
... <TextView android:id="@+id/text" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:text="Melody" android:textColor="@android:color/white" android:textSize="45sp"/> ...
java代碼部分不需要改變,下面再看效果圖:
效率如何?
為了查看操作耗時,我使用 Log 在 blur() 方法的開頭和結束地方分別計算了時間,然后查看時間差:
10-09 17:04:23.664 23665-23665/com.melodyxxx.blurdemo2 E/MainActivity: spend: 120ms
可以看到居然花了 120ms,顯然效率不夠高,有沒有優化的方法?(測試機型為 魅族 PRO 6)
效率優化
上面的是直接將原 ImageView 的 bitmap 直接模糊處理,效率不夠高,所以我們可以先將原圖片進行壓縮處理,然后在進行模糊,下面為關鍵代碼,scaleFactor 為壓縮比例大小,例如 scaleFactor 為 2,代表先將原圖壓縮為原來的 1/2,然后進行模糊,效率會高很多。
... Bitmap outputBitmap = Bitmap.createBitmap((int) (mTargetView.getMeasuredWidth() / scaleFactor), (int) (mTargetView.getMeasuredHeight() / scaleFactor), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(outputBitmap); canvas.translate(-mTargetView.getLeft() / scaleFactor, -mTargetView.getTop() / scaleFactor); canvas.scale(1 / scaleFactor, 1 / scaleFactor); Paint paint = new Paint(); paint.setFlags(Paint.FILTER_BITMAP_FLAG); canvas.drawBitmap(mInputBitmap, 0, 0, paint); ...
下面是 Demo 效果圖:
結果:
壓縮比例為 2 時:耗時 19 ms
壓縮比例為 8 時:耗時 2 ms
根據壓縮比例配合不同的模糊半徑可以達到不同模糊效果。
再來看 Demo 效果圖中拖動 SeekBar 可以動態的實現模糊效果,首先想到的方法是每次拖動時實時計算模糊,這樣的效率肯定不行,還會造成卡頓,我這里的方法是先將圖片最大化模糊一次設給上方 ImageView 的背景即可,然后 SeekBar 拖動時,只需要改變最上方或者下方圖片的透明度就可以達到上面的效果。
看完上述內容,你們對如何在Android中使用RenderScript實現一個毛玻璃模糊效果有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。