轉載:Android繪圖Canvas十八般武器之Shader詳解及實戰篇(下)

来源:http://www.cnblogs.com/xiaoxiaing/archive/2017/01/19/6306619.html
-Advertisement-
Play Games

LinearGradient 線性漸變渲染器 LinearGradient中文翻譯過來就是線性漸變的意思。線性漸變通俗來講就是給起點設置一個顏色值如#faf84d,終點設置一個顏色值如#CC423C,然後在一個區域內繪圖,這個圖像的顏色將呈現非常美妙的效果,顏色會從起點顏色到終點顏色過渡。給一張圖, ...


LinearGradient 線性漸變渲染器

LinearGradient中文翻譯過來就是線性漸變的意思。線性漸變通俗來講就是給起點設置一個顏色值如#faf84d,終點設置一個顏色值如#CC423C,然後在一個區域內繪圖,這個圖像的顏色將呈現非常美妙的效果,顏色會從起點顏色到終點顏色過渡。給一張圖,大家直觀感受一下 
這裡寫圖片描述

我們看LinearGradient的API,發現它只有兩個構造方法,非常簡單。

LinearGradient (float x0, 
                float y0, 
                float x1, 
                float y1, 
                int color0, 
                int color1, 
                Shader.TileMode tile)

//x0 和y0是顏色漸變的起點坐標。
//x1和y1是顏色漸變的終點坐標。
//color0是起點顏色值 
//color0是終點顏色值。
//tile 就是TileMode類型參數,這個我們上一篇已經講過了。

LinearGradient的用法。

//1   創建LinearGradient對象,並設置它的起點坐標,終點坐標,起點顏色值,終點顏色值,然後設置TileMode
mShader = new LinearGradient(0,0,w,0,Color.parseColor("#faf84d"),
                Color.parseColor("#CC423C"), Shader.TileMode.CLAMP);  

//2  將Shader賦值給Paint對象。
mPaint.setShader(mShader);  

//3  繪製圖形
canvas.drawRect(0,0,w,h/2,mPaint);

用法非常簡單。

LinearGradient還有一個構造方法。

LinearGradient (float x0, 
                float y0, 
                float x1, 
                float y1, 
                int[] colors, 
                float[] positions, 
                Shader.TileMode tile)

需要註意的是,這裡有一個int[] colorsfloat[] positions它們代表什麼意思呢? 
實際上LinearGradient除了可以指定起點顏色值和終點顏色值外,還有可以指定許多中間顏色值。就如彩虹一般。而colors[]數組存放的就是這樣的顏色值組合。大家看看代碼和圖片效果就可能直觀感受到。

//漸變的是一個顏色序列(#faf84d,#003449,#808080,#cc423c)
mShader = new LinearGradient(0,0,w,0,new int[]{Color.parseColor("#faf84d"),Color.parseColor("#003449"),
        Color.parseColor("#808080"),
        Color.parseColor("#CC423C")},null,Shader.TileMode.CLAMP);
mPaint.setShader(mShader);
canvas.drawRect(0,0,w,h/2,mPaint);

 

這裡寫圖片描述

顏色很豐富是不是?顏色從一個顏色過渡到另外一個顏色直到過渡到終點顏色。

大家有沒有註意到,我將上面代碼中的float[] positon置為null,而它代表了什麼呢?它其實與colors數組對應,代表了各個顏色值在位置,positions數組中的值大小範圍從0.0到1.0,0.0代表起點位置,1.0代表終點位置。如果這個數組被置為空的話,顏色就會平均分配。 ,如果這個數組不為空呢?我們結合代碼效果來講解。

mShader = new LinearGradient(0,0,w,0,new int[]{Color.parseColor("#faf84d"),Color.parseColor("#003449"),
        Color.parseColor("#808080"),
        Color.parseColor("#CC423C")},new float[]{0.0f,0.6f,0.8f,1.0f},Shader.TileMode.CLAMP);
mPaint.setShader(mShader);
canvas.drawRect(0,0,w,h/2,mPaint);

這裡寫圖片描述

代碼中colors[]並沒有改變,只是多了positon[],效果卻不一樣了。

new int[]{Color.parseColor("#faf84d"),Color.parseColor("#003449"),
        Color.parseColor("#808080"),
        Color.parseColor("#CC423C")}

new float[]{0.0f,0.6f,0.8f,1.0f}

// #faf84d對應的position值是0.0  所以為起點位置。
// #003449對應0.6    所以這個顏色位置起點到終點中間0.6比率的地方。
// #808080對應0.8    這個顏色在0.8比率的地方
// #cc423c對應1.0    這個顏色為終點處的顏色

需要註意的是,position[]數組中的數組最好是由小到大,這是為什麼呢?它不支持0.8 然後再到0.6之類。大家看代碼。

mShader = new LinearGradient(0,0,w,0,new int[]{Color.parseColor("#faf84d"),Color.parseColor("#003449"),
        Color.parseColor("#808080"),
        Color.parseColor("#CC423C")},new float[]{0.6f,0.8f,0.2f,0.0f},Shader.TileMode.CLAMP);

 

這裡寫圖片描述

可以看到顏色可以從0.6的位置過渡到0.8,後面的就不起作用了。

RadialGradient 環行渲染器

我喜歡稱它為徑向漸變,因為PHOTOSHOP中就對應有徑向漸變的概念。 
徑向漸變,所謂徑向就是輻射狀,由中心向四周輻射。 
徑向漸變也只有兩個構造方法,基本用法跟線性漸變差不多。

RadialGradient (float centerX, 
                float centerY, 
                float radius, 
                int centerColor, 
                int edgeColor, 
                Shader.TileMode tileMode)

//centerX  圓心的X坐標
//centerY  圓心的Y坐標
//radius   圓的半徑
//centerColor  中心顏色
//edgeColor   邊緣顏色
//tileMode   這個不用介紹了吧?

上代碼。

mShader = new RadialGradient(w/2,h/2,w/2,Color.parseColor("#faf84d"),
                Color.parseColor("#CC423C"), Shader.TileMode.CLAMP);
mPaint.setShader(mShader);
canvas.drawRect(0,0,w,h,mPaint);

效果: 
這裡寫圖片描述

RadialGradient (float centerX, 
                float centerY, 
                float radius, 
                int[] colors, 
                float[] stops, 
                Shader.TileMode tileMode)

同LinearGradient一樣,這裡也有一個顏色數組和位置數組,意義也是一樣的,stop[]也可以為null,如果為null的話,color[]數組的顏色就會平均分配在區域之中。否則,它對應的顏色就會按照比例填充。

mShader = new RadialGradient(w/2,h/2,w/2,new int[]{Color.parseColor("#00aa00"),Color.parseColor("#880033"),
        Color.parseColor("#F8795A"),
        Color.parseColor("#CC423C")},new float[]{0.0f,0.2f,0.8f,1.0f}, Shader.TileMode.CLAMP);
mPaint.setShader(mShader);
canvas.drawRect(0,0,w,h,mPaint);

 

這裡寫圖片描述

SweepGradient 梯度漸變渲染器

梯度漸變,或者叫做掃描漸變。我覺得掃描更適合吧,它是指從x軸出發,以逆時鐘為方向,以掃描360度形成的區域進行顏色的變換。

SweepGradient (float cx, 
                float cy, 
                int color0, 
                int color1)
//color0是起始顏色
//color1是終止顏色

代碼示例:

mShader = new SweepGradient(w/2,h/2,Color.RED,Color.BLUE);
mPaint.setShader(mShader);
canvas.drawRect(0,0,w,h,mPaint);

效果: 
這裡寫圖片描述

SweepGradient (float cx, 
                float cy, 
                int[] colors, 
                float[] positions)

 

大家應該也明白這個方法中每個參數的含義。

mShader = new SweepGradient(w/2,h/2,new int[]{Color.RED,Color.CYAN,Color.YELLOW,
                Color.GREEN,Color.MAGENTA,Color.BLUE},new float[]{0.0f,0.2f,0.3f,0.4f,0.8f,1.0f});
mPaint.setShader(mShader);
canvas.drawRect(0,0,w,h,mPaint);

我們把顏色豐富點,本來想弄成赤橙黃綠青藍紫,結果因為懶,就隨便弄了點,效果如下:

這裡寫圖片描述

ComposeShader 組合渲染器

混合渲染,在這裡我又開始稱Shader為渲染了,因為ComposeShader不僅僅用於顏色,它能將兩個Shader對象參考Xfermode規則進行顏色混合。

網上的一張圖: 
這裡寫圖片描述

這張圖詳細的解釋了混合模式的組合效果,我機會我也寫一篇相關博文。 
再看ComposeShader的兩個構造方法。

ComposeShader (Shader shaderA, 
                Shader shaderB, 
                Xfermode mode)


ComposeShader (Shader shaderA, 
                Shader shaderB, 
                PorterDuff.Mode mode)

接下來,我們寫代碼驗證一下。

實戰1

  1. 編寫1個BitmapShader.
  2. 編寫1個RadiasGradient。
  3. 將它們進行混合產生新的Shader.
  4. 以新的Shader繪製一個圓。
public class CircleView extends View {
    private Paint mPaint;
    private Shader mShader;

    public CircleView(Context context) {
        this(context,null);
    }

    public CircleView(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //這裡為了方便演示,將尺寸固定為400*400
        setMeasuredDimension(400,400);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int w = getWidth();
        int h = getHeight();
        int radius = w <= h ? w/2 : h/2;


        Bitmap bmp = BitmapFactory.decodeResource(getResources(),R.drawable.repeat);
        Bitmap result = Bitmap.createScaledBitmap(bmp,w,h,false);
        //1. 編寫1個BitmapShader.
        BitmapShader bitmapShader = new BitmapShader(result, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);

        //2. 編寫1個RadiasGradient。
        RadialGradient radialGradient = new RadialGradient(radius,radius,radius,Color.BLACK,Color.TRANSPARENT, Shader.TileMode.CLAMP);
        //3. 將它們進行混合產生新的Shader.
        ComposeShader composeShader = new ComposeShader(bitmapShader,radialGradient,new PorterDuffXfermode(PorterDuff.Mode.DST_IN));

        mPaint.setShader(composeShader);
        //4. 以新的Shader繪製一個圓。
        canvas.drawCircle(w/2,h/2,radius,mPaint);

    }
}

我們來看看混合後的效果是怎麼樣的。

這裡寫圖片描述

哇,好夢幻的狗狗。

實戰2 倒影功能

以前剛開始學Android的時候,項目裡面要用到倒影,當時的自己是寫不出來的,好在網上有現成的代碼可以copy。現在我們可以運用ComposeShader來實現這麼一個View。

需求分析

  1. 倒影與原圖比例為1:4。
  2. 倒影與原圖之間有5px的間隙。
  3. 倒影的下邊緣不能太平整了,要儘量跟真實的一致。

好了為了節省篇幅,我只粘貼onDraw()中的代碼。

protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //定義各種寬高
        int bmpWidth = 200;
        int bmpHeight = 200;
        int gap = 5;
        int reflectionHeight = bmpHeight / 4;

        //繪製原圖
        Bitmap bmp = BitmapFactory.decodeResource(getResources(),R.drawable.repeat);
        Bitmap result = Bitmap.createScaledBitmap(bmp,bmpWidth,bmpHeight,false);
        canvas.drawBitmap(result,0,0,null);

        canvas.save();
        //向下移動準備在原圖下方繪製倒影
        canvas.translate(0,bmpHeight+gap);
        Matrix m = new Matrix();
        m.postScale(-1f,1f);
        m.postRotate(-180);
        //將原圖水平翻轉
        Bitmap texture = Bitmap.createBitmap(result,0,0,result.getWidth(),result.getHeight(),m,false);
        //創建BitmapShader和LinearShader。
        BitmapShader bitmapShader = new BitmapShader(texture, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
        LinearGradient linearGradient = new LinearGradient(0,0,0,reflectionHeight,Color.BLACK,Color.TRANSPARENT, Shader.TileMode.CLAMP);
        ComposeShader composeShader = new ComposeShader(bitmapShader,linearGradient,new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        mPaint.setShader(composeShader);
        //以混合模式繪製矩形區域,可以獲得倒影效果。
        canvas.drawRect(0,0,bmpWidth,reflectionHeight,mPaint);

        canvas.restore();

}

效果: 
這裡寫圖片描述

倒影出來了。

Android繪圖Canvas十八般武器之Shader詳解及實戰篇(上)


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 今天來到打開昨天的項目運行正常,然後改動了一點代碼編譯報錯: 把代碼改動的地方恢復還是一隻再報這個錯誤,想到了iOS開發中遇到莫名的錯誤第一步就是clean一下,重新編譯一下項目。Android Studio更好,直接有Rebuild功能(Build選項裡面),重新build項目後,錯誤消失,正常運 ...
  • 知識點: 1.UINavigationController 2.UINavigationItem 3.UINavigationBar 4.UINavigationController視圖切換 UINavigationController 1.什麼是導航控制器 作用:管理視圖控制器 2.UINavig ...
  • UITextField使用 1.創建方式 例: UITextField *text = [[UITextField alloc]initWithFrame:CGRectMake(20, 20, 130, 30)]; 2.常用方法和屬性 1)邊框樣式 @property(nonatomic) UITe ...
  • 今天學習了新的功能那就是滑動刪除數據。先看一下效果 我想這個效果大家都很熟悉吧。是不是在qq上看見過這個效果。俗話說好記性不如賴筆頭,為了我的以後,為了跟我一樣自學的小伙伴們,我把我的代碼粘貼在下麵。 activity_lookstaff.xml delete_btn.xml d_delete_bt ...
  • Android Studio導入Eclipse項目有兩種方法,一種是直接把Eclipse項目導入Android Studio,另一種是在Eclipse項目裡面進行轉換,然後再導入Android Studio。 1. 直接導入 打開Android Studio,如果裡面已經打開了項目,選擇關閉當前的項 ...
  • 打開Eclipse以後,一直在Android sdk content loader 0%,等了很長時間都沒有變,解決的方法是Project->Clean->Clean all projects,等一會兒就正常了。 ...
  • 由[OpenDigg](http://www.opendigg.com/) 出品的iOS開源項目周報第五期來啦。我們的iOS開源周報集合了OpenDigg一周來新收錄的優質的[iOS開源項目](http://www.opendigg.com/tags/ios),方便iOS開發人員便捷的找到自己需要的... ...
  • iOS開發中,我們經常遇到獲取拍照、相冊中圖片的功能,就必然少不了UIImagePickerController,但是我們發現當我們使用它的時候,它的頁面是英文的,看著很彆扭,國人還是比較喜歡看中文界面,下麵來看看我們怎麼把它變成中文界面的吧! 只需下麵兩步就可以了: Project-->Info- ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...