在上一篇文章中,一起學習了通過設定畫筆風格來實現圖形變換,沒讀過的朋友可以點擊下面鏈接:
http://www.cnblogs.com/fuly550871915/p/4886455.html
是不是覺得自己學到的知識更多了呢?那么再多學一點總沒壞處。在本篇文章中,將會一起學習通過給畫筆設定Shader屬性,實現圖形變換。並帶領讀者一起實現兩個實際例子,圖片渲染器和線性渲染器。有沒有發現我們的畫筆特別強大呢??確實,我們曾經給它設置過顏色矩陣屬性,設置過xfermode風格屬性,現在又來設定Shader屬性。好了,廢話不多說了,進入本章的主要內容吧。
一、基礎知識
渲染效果大家都應該見到過,比如下面的這張圖片。
上面是一張中規中矩的線性渲染的圖片,從藍色渲染到紅色。但是在android中,有一個很奇葩的渲染方法,叫圖片渲染。什么是圖片渲染呢??沒法說清楚,到下面的實戰項目中大家看到效果就明白了。其他的渲染,比如線性漸變,矩形漸變等都是大家熟知的了。
對於給畫筆設定圖片渲染,首先要實例化一個圖片渲染對象,然后再設定給畫筆。示例代碼如下:
//初始化圖片渲染器 mBitmapShader = new BitmapShader(bmp, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT); //將畫筆綁定圖片渲染器 paint.setShader(mBitmapShader);
其中bmp是一個Bitmap圖片,而渲染的模式有Shader.TileMode.REPEAT,Shader.TileMode.CLAMP,Shader.TileMode.MIRROR。分別是重復模式,拉伸邊緣像素模式,鏡像模式。這幾種模式你現在無法理解,到實戰項目中,我們會演示效果,到時候你就明白了。上面的代碼是x方向和y方向都設定為重復渲染模式。
對於給畫筆設定普通的渲染器,比如說線性渲染,一句代碼搞定,如下:
//方法new LinearGradient(x0, y0, x1, y1, color0, color1, tile) //設置線性渲染器,(x0,y0)是起點坐標,(x1,y1)是終點坐標 //從color0渲染到color1,當然這里的color也可以改為透明度 //最后的tile表示選擇一種渲染模式 paint.setShader(new LinearGradient(0, 0, 300, 300, Color.BLUE, Color.RED, Shader.TileMode.CLAMP));
注釋中說的很清楚了,至於渲染模式,上面也有解釋。
好了,然我們快進入實戰,看看這些方法到底是怎么用的吧。
二、圖片渲染實戰
這里我們需要一張圖片資源,讀者可以替換為自己的圖片,建議圖片選的小一點盡量。這樣效果看起來方便一些。在上一篇文章的代碼基礎上我們接着往下寫。首先新建MyShaderView繼承自view。代碼中的注釋很詳細,在代碼中用畫筆綁定了圖片渲染器然后畫了一個圓出來。如下:
1 package com.fuly.image; 2 3 import android.content.Context; 4 import android.graphics.Bitmap; 5 import android.graphics.BitmapFactory; 6 import android.graphics.BitmapShader; 7 import android.graphics.Canvas; 8 import android.graphics.Paint; 9 import android.graphics.Shader; 10 import android.util.AttributeSet; 11 import android.view.View; 12 /** 13 * 利用渲染器shader變換圖像 14 * @author fuly1314 15 * 16 */ 17 public class MyShaderView extends View{ 18 19 private Bitmap bmp; 20 private Paint paint = new Paint(); 21 private BitmapShader mBitmapShader;//圖片渲染器 22 23 24 public MyShaderView(Context context) { 25 super(context); 26 } 27 public MyShaderView(Context context, AttributeSet attrs) { 28 super(context, attrs); 29 30 } 31 public MyShaderView(Context context, AttributeSet attrs, int defStyleAttr) { 32 super(context, attrs, defStyleAttr); 33 } 34 35 36 protected void onDraw(Canvas canvas) { 37 38 super.onDraw(canvas); 39 40 bmp = BitmapFactory.decodeResource(getResources(), R.drawable.hudie2); 41 //初始化圖片渲染器 42 mBitmapShader = new BitmapShader(bmp, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT); 43 //將畫筆綁定圖片渲染器 44 paint.setShader(mBitmapShader); 45 46 canvas.drawCircle(150, 150, 300, paint); 47 48 } 49 50 }
然后新建布局imageshader.xml把這個view裝進去。如下:
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" 6 android:gravity="center"> 7 8 <com.fuly.image.MyShaderView 9 android:layout_marginLeft="20dp" 10 android:layout_marginTop="20dp" 11 android:layout_width="wrap_content" 12 android:layout_height="wrap_content"/> 13 14 </LinearLayout>
接着新建活動ShaderActivity顯示這個布局,此時別忘記給這個活動注冊。如下:
1 package com.fuly.image; 2 3 import android.app.Activity; 4 import android.os.Bundle; 5 6 public class ShaderActivity extends Activity{ 7 8 9 protected void onCreate(Bundle savedInstanceState) { 10 11 super.onCreate(savedInstanceState); 12 setContentView(R.layout.imageshader); 13 14 } 15 16 }
最后給MainActivity中的按鈕添加監聽事件,如下:
1 package com.fuly.image; 2 3 import android.os.Bundle; 4 import android.view.View; 5 import android.app.Activity; 6 import android.content.Intent; 7 8 9 public class MainActivity extends Activity { 10 11 12 protected void onCreate(Bundle savedInstanceState) { 13 super.onCreate(savedInstanceState); 14 setContentView(R.layout.activity_main); 15 } 16 17 //下面是按鈕事件 18 public void btnMatrix(View v){ 19 Intent intent = new Intent(this,MatrixActivity.class); 20 startActivity(intent); 21 } 22 public void btnXFermode(View v){ 23 Intent intent = new Intent(this,XFermodeActivity.class); 24 startActivity(intent); 25 } 26 public void btnShader(View v){ 27 Intent intent = new Intent(this,ShaderActivity.class); 28 startActivity(intent); 29 } 30 31 32 }
好了,快運行程序看看效果。如下:
注意在圖片渲染中,我們使用了REPEAT模式。從效果來看其實就是用我們的這張小蝴蝶的圖片來填充我們畫的圓,如果發現圖片太小,填充不完怎么辦,那就不斷重復畫這個圖片直到填充完為止。這下你明白什么是REPEAT模式了吧。下面我們將MyShaderView的第42行,即實例化圖片渲染的代碼改變一下,變成MIRROR模式,如下:
//初始化圖片渲染器 42 mBitmapShader = new BitmapShader(bmp, Shader.TileMode.MIRROR, Shader.TileMode.MIRROR);
只改這一個地方,然后重新運行程序,效果圖如下:
有沒有發現跟REPEAT模式有什么不同?也就是說在填充的時候,發現圖片不夠大,那就畫它的鏡像(即在鏡子里的圖像,也就是倒影)來填充,如此反復,直到填充完為止。這既是MIRROR模式的效果了。那么CLAMP模式又是什么樣的呢?我們仍然修改第42行代碼,如下:
//初始化圖片渲染器 mBitmapShader = new BitmapShader(bmp, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
為了讓顯示效果更好一點,我們替換為另外一張圖片,此時要修改相應的獲取bmp的代碼。這個即修改第40的代碼即可。我就不貼出來了。然后運行程序,效果如下:
上圖中,左側是效果圖,右側就是我所使用的那張原圖。可以看到,CLAMP模式的意思其實當發現原來圖片不夠填充的時候,就拉伸原圖片邊緣的像素直到填充滿為止。
好了。經過那上面的三輪實驗,相信你不經對着三種模式有所了解,而且對圖片渲染也很熟悉了。那么下面就讓我們來實現常規的渲染,比如線性漸變。
三、線性漸變實戰
在這里簡單起見,我就簡單的單純的只實現一個線性漸變的效果吧。目的是為讓大家看看,普通的渲染是怎么綁定畫筆的。目前來說,掌握這個就達到這篇文章的目的了。首先老規矩,新建LinearShaderView繼承自view,在這里的代碼中,將為畫筆綁定一個線性漸變的渲染,並用它畫出一個矩形。代碼如下:
1 package com.fuly.image; 2 3 import android.content.Context; 4 import android.graphics.Bitmap; 5 import android.graphics.BitmapFactory; 6 import android.graphics.BitmapShader; 7 import android.graphics.Canvas; 8 import android.graphics.Color; 9 import android.graphics.LinearGradient; 10 import android.graphics.Paint; 11 import android.graphics.Shader; 12 import android.util.AttributeSet; 13 import android.view.View; 14 /** 15 * 利用線性渲染器shader變換圖像 16 * @author fuly1314 17 * 18 */ 19 public class LinearShaderView extends View{ 20 21 private Paint paint = new Paint(); 22 23 24 25 public LinearShaderView(Context context) { 26 super(context); 27 } 28 public LinearShaderView(Context context, AttributeSet attrs) { 29 super(context, attrs); 30 31 } 32 public LinearShaderView(Context context, AttributeSet attrs, int defStyleAttr) { 33 super(context, attrs, defStyleAttr); 34 } 35 36 37 protected void onDraw(Canvas canvas) { 38 39 super.onDraw(canvas); 40 //方法new LinearGradient(x0, y0, x1, y1, color0, color1, tile) 41 //設置線性渲染器,(x0,y0)是起點坐標,(x1,y1)是終點坐標 42 //從color0渲染到color1,當然這里的color也可以改為透明度 43 //最后的tile表示選擇一種渲染模式 44 paint.setShader(new LinearGradient(0, 0, 300, 300, Color.BLUE, Color.RED, 45 Shader.TileMode.CLAMP)); 46 //初始化圖片渲染器 47 48 canvas.drawRect(0, 0, 300, 300, paint); 49 50 } 51 52 }
新建布局imagelinearshader.xml,將這個布局加進去,代碼如下:
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" 6 android:gravity="center"> 7 8 <com.fuly.image.LinearShaderView 9 10 android:layout_width="wrap_content" 11 android:layout_height="wrap_content"/> 12 13 </LinearLayout>
然后該新建活動了LinearShaderActivity用來顯示我們的布局,代碼如下:
1 package com.fuly.image; 2 3 import android.app.Activity; 4 import android.os.Bundle; 5 6 public class LinearShaderActivity extends Activity{ 7 8 9 protected void onCreate(Bundle savedInstanceState) { 10 11 super.onCreate(savedInstanceState); 12 setContentView(R.layout.imagelinearshader); 13 14 } 15 16 }
最后呢,就是MainActivity中的按鈕事件了,如下:
1 package com.fuly.image; 2 3 import android.os.Bundle; 4 import android.view.View; 5 import android.app.Activity; 6 import android.content.Intent; 7 8 9 public class MainActivity extends Activity { 10 11 12 protected void onCreate(Bundle savedInstanceState) { 13 super.onCreate(savedInstanceState); 14 setContentView(R.layout.activity_main); 15 } 16 17 //下面是按鈕事件 18 public void btnMatrix(View v){ 19 Intent intent = new Intent(this,MatrixActivity.class); 20 startActivity(intent); 21 } 22 public void btnXFermode(View v){ 23 Intent intent = new Intent(this,XFermodeActivity.class); 24 startActivity(intent); 25 } 26 public void btnShader(View v){ 27 Intent intent = new Intent(this,ShaderActivity.class); 28 startActivity(intent); 29 } 30 public void btnLShader(View v){ 31 Intent intent = new Intent(this,LinearShaderActivity.class); 32 startActivity(intent); 33 } 34 35 36 }
然后運行程序,效果如下:
好了,至此,你有沒有學會怎么給畫筆綁定普通的渲染呢?上面實現的效果比較簡單,其實利用線性漸變結合xfermode風格可以實現常見的水面倒影效果,這個有興趣可以自己百度下相關案例。
不知道你有沒有發現,不知不覺間我們已經實現了4個按鈕的效果了。還有最后一個按鈕“像素塊實驗”沒有實現了,下一篇文章中,我們就來看看這個效果吧。然后這個圖形變換基礎系列文章就完結了。