Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android Paint setXfermode()方法講解

android Paint setXfermode()方法講解

編輯:關於Android編程

看過很多開源代碼效果,發現裡面的代碼很多地方都用到這函數,於是想花些時間研究下這個,我現在寫博客一般不可能一下子就寫完,因為我也要查資料,寫代碼去驗證其效果,而且還要找下好的效果,看能不能用這篇博客知識能實現出來的,整理出來,切入正題!

paint的setXfermode()是圖形混合模式,多叫混合模式了,肯定是二張以上的圖形才可以,看下Paint類中定義這個方法:

 

public Xfermode setXfermode(Xfermode xfermode) {
    long xfermodeNative = 0;
    if (xfermode != null)
        xfermodeNative = xfermode.native_instance;
    native_setXfermode(mNativePaint, xfermodeNative);
    mXfermode = xfermode;
    return xfermode;
}
發現函數中接受Xfermode形參,點擊Xfermode類看看啥東西,

 

 

public class Xfermode {

    protected void finalize() throws Throwable {
        try {
            finalizer(native_instance);
        } finally {
            super.finalize();
        }
    }

    private static native void finalizer(long native_instance);

    long native_instance;
}
什麼玩意,就這幾行代碼,而且還有一個被native修飾的方法,這就超越了上層的知識結構,表示不懂,所以不看了,ctrl+T,發現有三個子類,

 

\

現在就分別講一下這三個類怎麼使用,以及其能實現什麼效果

AvoidXfermode

這是一個關於顏色模式的類,這是我自己取得,網上很多叫--指定了一個顏色和容差,強制Paint避免在它上面繪圖(或者只在它上面繪圖),不管它叫什麼,

看下AvoidXfermode的類

 

@Deprecated
public class AvoidXfermode extends Xfermode {

    // these need to match the enum in AvoidXfermode.h on the native side
    public enum Mode {
        AVOID   (0),    //!< draw everywhere except on the opColor
        TARGET  (1);    //!< draw only on top of the opColor
        
        Mode(int nativeInt) {
            this.nativeInt = nativeInt;
        }
        final int nativeInt;
    }
    
    /** This xfermode draws, or doesn't draw, based on the destination's
     * distance from an op-color.
     *
     * There are two modes, and each mode interprets a tolerance value.
     *
     * Avoid: In this mode, drawing is allowed only on destination pixels that
     * are different from the op-color.
     * Tolerance near 0: avoid any colors even remotely similar to the op-color
     * Tolerance near 255: avoid only colors nearly identical to the op-color
     
     * Target: In this mode, drawing only occurs on destination pixels that
     * are similar to the op-color
     * Tolerance near 0: draw only on colors that are nearly identical to the op-color
     * Tolerance near 255: draw on any colors even remotely similar to the op-color
     */
    public AvoidXfermode(int opColor, int tolerance, Mode mode) {
        if (tolerance < 0 || tolerance > 255) {
            throw new IllegalArgumentException("tolerance must be 0..255");
        }
        native_instance = nativeCreate(opColor, tolerance, mode.nativeInt);
    }

    private static native long nativeCreate(int opColor, int tolerance,
                                            int nativeMode);
}
發現它都沒有自己的方法,就是一個構造函數,

 

 

public AvoidXfermode(int opColor, int tolerance, Mode mode) {
    if (tolerance < 0 || tolerance > 255) {
        throw new IllegalArgumentException("tolerance must be 0..255");
    }
    native_instance = nativeCreate(opColor, tolerance, mode.nativeInt);
}
參數說明:

 

int opColor:是一個16進制的顏色值

int tolerance:看的出來這個取值范圍為[0,255]

Mode mode值在這個類下面定義了一個枚舉就二種值一個是AVOID,一種是TARGET,

現在寫一個例子更好裡面上面三個參數,

 


package com.example.myapplication;
import android.content.Context;
import android.graphics.AvoidXfermode;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
/**
 * Created by admin on 2016/7/2.
 */
public class MyView extends View {
    private Paint mPaint;
    private Bitmap mBitmap;
    public MyView(Context context) {
        this(context,null);
    }
    public MyView(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }
    public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }
    private void init() {
        mPaint = new Paint();
        mBitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.bb);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.setColor(Color.RED);
        canvas.drawBitmap(mBitmap,new Matrix(),mPaint);
        mPaint.setXfermode(new AvoidXfermode(Color.WHITE,100, AvoidXfermode.Mode.TARGET));
        canvas.drawRect(0,0,mBitmap.getWidth(),mBitmap.getHeight(),mPaint);
    }
}
效果圖:

 

\

尼瑪發現這不是下面一個畫布把上一個畫布擋住了麼,還什麼混合模式,這個跟硬件加速有關,大家手機中設置界面有關一個叫GPU的東西吧,是不是和CPU很像啊,GPU的出現就是為了繪制圖形圖像的,在view中禁止GPU硬件加速的方法是:

 

setLayerType(View.LAYER_TYPE_SOFTWARE, null);這個在構造函數中設置就行
現在再看下效果:

 

\

把硬件加速禁止了效果就出來了,看下onDraw()中的代碼,canvas是2個畫布,

\

現在我把AvoidXfermode構造函數中的第二個參數變一下,看下其效果,之前傳的是100,現在傳200,效果:

\

之前說了這個值最大是255,現在就把它設置為255

 

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    mPaint.setColor(Color.RED);
    canvas.drawBitmap(mBitmap,new Matrix(),mPaint);
    mPaint.setXfermode(new AvoidXfermode(Color.WHITE,255, AvoidXfermode.Mode.TARGET));
    canvas.drawRect(0,0,mBitmap.getWidth(),mBitmap.getHeight(),mPaint);
}
效果:

 

\

現在傳0試試:

 

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    mPaint.setColor(Color.RED);
    canvas.drawBitmap(mBitmap,new Matrix(),mPaint);
    mPaint.setXfermode(new AvoidXfermode(Color.WHITE,0, AvoidXfermode.Mode.TARGET));
    canvas.drawRect(0,0,mBitmap.getWidth(),mBitmap.getHeight(),mPaint);
}
效果:

 

\

發現0是透明的效果,現在看第三個形參Mode,這個是傳遞AvoidXfermode.Mode.TARGET

AvoidXfermode.Mode.TARGET:會判斷畫布(也就是canvas,而canvas顏色是通過Paint設置的)上的顏色是否會有跟opColor(AvoidXfermode構造函數第一個形參)有一樣的顏色,比如我opColor是白色,那麼在TARGET模式下就會去判斷我們的畫布上是否有存在白色的地方,如果有,則把該區域“染”上一層我們畫筆定義的顏色,否則不“染”色

AvoidXfermode.Mode.AVOID:跟上面剛好相反,

PorterDuffXfermode

構造函數:

 

public PorterDuffXfermode(PorterDuff.Mode mode) {
    this.mode = mode;
    native_instance = nativeCreateXfermode(mode.nativeInt);
}

發現構造函數就一個值,這些值是定義在PorterDuff類中

 

public enum Mode {
    /** [0, 0] */
    CLEAR       (0),
    /** [Sa, Sc] */
    SRC         (1),
    /** [Da, Dc] */
    DST         (2),
    /** [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] */
    SRC_OVER    (3),
    /** [Sa + (1 - Sa)*Da, Rc = Dc + (1 - Da)*Sc] */
    DST_OVER    (4),
    /** [Sa * Da, Sc * Da] */
    SRC_IN      (5),
    /** [Sa * Da, Sa * Dc] */
    DST_IN      (6),
    /** [Sa * (1 - Da), Sc * (1 - Da)] */
    SRC_OUT     (7),
    /** [Da * (1 - Sa), Dc * (1 - Sa)] */
    DST_OUT     (8),
    /** [Da, Sc * Da + (1 - Sa) * Dc] */
    SRC_ATOP    (9),
    /** [Sa, Sa * Dc + Sc * (1 - Da)] */
    DST_ATOP    (10),
    /** [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc] */
    XOR         (11),
    /** [Sa + Da - Sa*Da,
         Sc*(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)] */
    DARKEN      (16),
    /** [Sa + Da - Sa*Da,
         Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)] */
    LIGHTEN     (17),
    /** [Sa * Da, Sc * Dc] */
    MULTIPLY    (13),
    /** [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] */
    SCREEN      (14),
    /** Saturate(S + D) */
    ADD         (12),
    OVERLAY     (15);
發現一共有18個值,關於這裡的算法我是不懂,但是我可以每個值我寫個例子出來,看看效果,知道了什麼意思,就可以寫出來不一樣的效果了就行

 

先看google文檔給我們的一張圖:

\

相信這張圖大家在網上很容易看到,

 

這裡有個概念就是DST和SRC,DST是指目標圖形,SCR是指源圖形,現在寫個例子說明下:

 

package com.example.xfermode;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;

/**
 * Created by admin on 2016/7/4.
 */
public class MyView extends View {
    private int width = 200;
    private int height = 200;
    private Bitmap dstBmp;
    private Bitmap srcBmp;
    private Paint mPaint;
    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        dstBmp = getDSTBitmap(width,height);
        srcBmp = getSRCBitmap(width,height);
        mPaint = new Paint();
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);//禁止硬件加速
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawBitmap(dstBmp, 0, 0, mPaint);//繪制目標圖形,目標圖形是一個圓
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(srcBmp, width/2, height/2, mPaint);//繪制源目標
        mPaint.setXfermode(null);//將畫筆去除Xfermode
    }
    public Bitmap getDSTBitmap(int w, int h) {
        Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(bm);//創建一個新的畫布,以後在畫布上繪制的圖形都是繪制在bm上
        Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
        p.setColor(0xFFFFCC44);
        c.drawOval(new RectF(0, 0, w, h), p);
        return bm;
    }
    public  Bitmap getSRCBitmap(int w, int h) {
        Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(bm);
        Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
        p.setColor(0xFF66AAFF);
        c.drawRect(0, 0,w,h, p);
        return bm;
    }
}
效果:

 

\

如果不設置mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));這行代碼看下效果是怎麼樣的,

\

通過上下二張圖就看出來了paint設置xfermode()的效果來了,太強大了,

PorterDuffXfermode這個類中的Porter和Duff是兩個人名,這兩個人在1984年一起寫了一篇名為《Compositing Digital Images》的論文,我們知道,一個像素是由RGBA四個分量組成的,該論文就論述了如何實現不同數字圖像的像素之間是如何進行混合的,該論文提出了多種像素混合的模式

現在對什麼是源圖形和目標圖形做個簡單的說明:

\

說明一點,源圖形可以是多個,比如下面:

 

package com.example.xfermode;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;

/**
 * Created by admin on 2016/7/4.
 */
public class MyView extends View {
    private int width = 200;
    private int height = 200;
    private Bitmap dstBmp;
    private Bitmap srcBmp;
    private Paint mPaint;
    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        dstBmp = getDSTBitmap(width,height);
        srcBmp = getSRCBitmap(width,height);
        mPaint = new Paint();
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);//禁止硬件加速
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawBitmap(dstBmp, 0, 0, mPaint);//繪制目標圖形,目標圖形是一個圓
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(srcBmp, width/2, height/2, mPaint);//繪制源目標
        mPaint.setColor(Color.RED);
        canvas.drawRect(0,0,100,100,mPaint);
        mPaint.setColor(Color.GREEN);
        canvas.drawRect(100,0,200,100,mPaint);
        mPaint.setXfermode(null);//將畫筆去除Xfermode
    }
    public Bitmap getDSTBitmap(int w, int h) {
        Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(bm);//創建一個新的畫布,以後在畫布上繪制的圖形都是繪制在bm上
        Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
        p.setColor(0xFFFFCC44);
        c.drawOval(new RectF(0, 0, w, h), p);
        return bm;
    }
    public  Bitmap getSRCBitmap(int w, int h) {
        Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(bm);
        Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
        p.setColor(0xFF66AAFF);
        c.drawRect(0, 0,w,h, p);
        return bm;
    }
}
效果圖:

 

\

這個是不是有點像分布圖,

一般我們在調用canvas.drawXXX()方法時都會傳入一個畫筆Paint對象,Android在繪圖時會先檢查該畫筆Paint對象有沒有設置Xfermode,如果沒有設置Xfermode,那麼直接將繪制的圖形覆蓋Canvas對應位置原有的像素;如果設置了Xfermode,那麼會按照Xfermode具體的規則來更新Canvas中對應位置的像素顏色,關於具體的算法不懂,

發現我xfermode設置的是src_in模式和Google給的不一樣,是不是Google錯了,

上面講了一個SRC_IN模式,現在把其他模式也講下,

 

1、Mode.ADD(飽和度相加)

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawBitmap(dstBmp, 0, 0, mPaint);//繪制目標圖形,目標圖形是一個圓
    mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD));
    canvas.drawBitmap(srcBmp, width/2, height/2, mPaint);//繪制源目標
    mPaint.setXfermode(null);//將畫筆去除Xfermode
}
效果:

 

\

 

2、Mode.LIGHTEN(變亮)

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawBitmap(dstBmp, 0, 0, mPaint);//繪制目標圖形,目標圖形是一個圓
    mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN));
    canvas.drawBitmap(srcBmp, width/2, height/2, mPaint);//繪制源目標
    mPaint.setXfermode(null);//將畫筆去除Xfermode
}
效果: \   我們可以利用這個實現一些效果,比如給一張圖片染色,下面是我喜歡的芷若妹妹原圖, \ 現在用代碼讓這張圖片變的模糊點
public class MyView3 extends View {
    private Paint mPaint;
    private Bitmap bitmap = null;
    public MyView3(Context context) {
        super(context);
    }
    public MyView3(Context context, AttributeSet attrs) {
        super(context, attrs);
        bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.aa);
        mPaint = new Paint();
    }
    public MyView3(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawBitmap(bitmap, 0, 0, mPaint);
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN));
        mPaint.setColor(0x70ffffff);
        canvas.drawRect(0,0,bitmap.getWidth(),bitmap.getHeight(),mPaint);
    }
}
效果: \

3、Mode.DARKEN(變暗)

public class MyView3 extends View {
    private Paint mPaint;
    private Bitmap bitmap = null;
    public MyView3(Context context) {
        super(context);
    }
    public MyView3(Context context, AttributeSet attrs) {
        super(context, attrs);
        bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.aa);
        mPaint = new Paint();
    }
    public MyView3(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawBitmap(bitmap, 0, 0, mPaint);
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DARKEN));
        mPaint.setColor(0x70ffffff);
        canvas.drawRect(0,0,bitmap.getWidth(),bitmap.getHeight(),mPaint);
    }
}
效果: \

4、Mode.MULTIPLY

public class MyView extends View {
    private int width = 200;
    private int height = 200;
    private Bitmap dstBmp;
    private Bitmap srcBmp;
    private Paint mPaint;
    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        dstBmp = getDSTBitmap(width,height);
        srcBmp = getSRCBitmap(width,height);
        mPaint = new Paint();
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);//禁止硬件加速
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawBitmap(dstBmp, 0, 0, mPaint);//繪制目標圖形,目標圖形是一個圓
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
        canvas.drawBitmap(srcBmp, width/2, height/2, mPaint);//繪制源目標
        mPaint.setXfermode(null);//將畫筆去除Xfermode
    }
    public Bitmap getDSTBitmap(int w, int h) {
        Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(bm);//創建一個新的畫布,以後在畫布上繪制的圖形都是繪制在bm上
        Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
        p.setColor(0xFFFFCC44);
        c.drawOval(new RectF(0, 0, w, h), p);
        return bm;
    }
    public  Bitmap getSRCBitmap(int w, int h) {
        Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(bm);
        Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
        p.setColor(0xFF66AAFF);
        c.drawRect(0, 0,w,h, p);
        return bm;
    }
}
效果: \ 發現在目標圖形和源圖形的交集的區域顏色變了

5、Mode.OVERLAY

public class MyView extends View {
    private int width = 200;
    private int height = 200;
    private Bitmap dstBmp;
    private Bitmap srcBmp;
    private Paint mPaint;
    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        dstBmp = getDSTBitmap(width,height);
        srcBmp = getSRCBitmap(width,height);
        mPaint = new Paint();
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);//禁止硬件加速
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawBitmap(dstBmp, 0, 0, mPaint);//繪制目標圖形,目標圖形是一個圓
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.OVERLAY));
        canvas.drawBitmap(srcBmp, width/2, height/2, mPaint);//繪制源目標
        mPaint.setXfermode(null);//將畫筆去除Xfermode
    }
    public Bitmap getDSTBitmap(int w, int h) {
        Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(bm);//創建一個新的畫布,以後在畫布上繪制的圖形都是繪制在bm上
        Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
        p.setColor(0xFFFFCC44);
        c.drawOval(new RectF(0, 0, w, h), p);
        return bm;
    }
    public  Bitmap getSRCBitmap(int w, int h) {
        Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(bm);
        Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
        p.setColor(0xFF66AAFF);
        c.drawRect(0, 0,w,h, p);
        return bm;
    }
}
效果: \ 6:Mode.SCREEN \ 7:Mode.SRC 效果: \ 8:Mode.SRC_IN 效果: \ 這個第一次就講了這個模式, 如果把源圖形改成透明的,
public  Bitmap getSRCBitmap(int w, int h) {
    Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
    Canvas c = new Canvas(bm);
    Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
    p.setColor(0x00ffffff);
    c.drawRect(0, 0,w,h, p);
    return bm;
}
效果: \ 發現當源圖形是透明的時候,不管是設置Mode.SRC還是Mode.SRC_IN效果是一樣的, 利用這個模式可以實現一個倒影效果: 關鍵代碼如下:
public static Bitmap compoundBitmap(Context contxt, int resId){
    Bitmap originalBitmap = BitmapFactory.decodeResource(contxt.getResources(),resId);//把資源圖片變成一個Bitmap對象
    //生成下面的一半圖片
    Matrix matrix = new Matrix();
    matrix.setScale(1,-1);
    Bitmap invertBitmap = Bitmap.createBitmap(originalBitmap,0,originalBitmap.getHeight()/2,originalBitmap.getWidth(),originalBitmap.getHeight()/2,matrix,false);
    //創建一個空的位圖
    Bitmap compoundBitmap =  Bitmap.createBitmap(originalBitmap.getWidth(),originalBitmap.getHeight()+invertBitmap.getHeight()+10, Bitmap.Config.ARGB_8888);//+10是為了2張圖片之間有空隙

    Canvas canvas = new Canvas(compoundBitmap);
    canvas.drawBitmap(originalBitmap,0,0,null);
    canvas.drawBitmap(invertBitmap,0,originalBitmap.getHeight()+10,null);
    Paint paint = new Paint();
    // 設置漸變顏色
    LinearGradient shader = new LinearGradient(0, originalBitmap.getHeight() + 5, 0, compoundBitmap.getHeight(), 0x70ffffff, 0x00ffffff, Shader.TileMode.CLAMP);
    paint.setShader(shader);
    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
    canvas.drawRect(0, originalBitmap.getHeight() + 5, originalBitmap.getWidth(), compoundBitmap.getHeight(), paint);
    return  compoundBitmap;
}
效果: \ 9:Mode.SRC_OUT 效果圖: \   如果看不出來效果,就寫2個矩形試試,看齊效果:
public class MyView3 extends View {
    private Paint mPaint;
    private Bitmap bitmap = null;
    private Bitmap srcBitmap = null;
    public MyView3(Context context) {
        super(context);
    }
    public MyView3(Context context, AttributeSet attrs) {
        super(context, attrs);
        srcBitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.dog_shade);
        mPaint = new Paint();
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);//禁止硬件加速
    }
    public MyView3(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.setColor(Color.GREEN);
        canvas.drawRect(10,10,100,100,mPaint);
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        mPaint.setColor(Color.RED);
        canvas.drawRect(10,10,100,100,mPaint);
    }
}
效果: \ 你會發現目標圖形綠色完全被源圖形蓋住了,是不是想到了什麼,對,橡皮擦效果就是這樣的,目標圖形是一張圖片,上面可以是其他顏色,然後塗上去,現在就實現下橡皮擦效果,它的原理講下, \ 代碼:
package com.example.xfermode;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * Created by admin on 2016/7/4.
 */
public class MyView3 extends View {
    private Paint mPaint;
    private Bitmap bitmap = null;
    private Bitmap srcBitmap = null;
    private Path mPath;

    private float firstDownX;
    private float firstDownY;
    public MyView3(Context context) {
        super(context);
    }
    public MyView3(Context context, AttributeSet attrs) {
        super(context, attrs);
        srcBitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.aa);//目標圖片
        //創建一個空位圖 寬和高和源圖片一樣
        bitmap = Bitmap.createBitmap(srcBitmap.getWidth(),srcBitmap.getHeight(), Bitmap.Config.ARGB_8888);
        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(30);
        mPath = new Path();
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);//禁止硬件加速
    }
    public MyView3(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Canvas newCanvas = new Canvas();//創建一個畫布
        newCanvas.setBitmap(bitmap);//把一個空位圖作用於畫布上,以後在這個畫布上繪制的圖形都在這個位圖上顯示
        newCanvas.drawPath(mPath,mPaint);//繪制路徑
        canvas.drawBitmap(bitmap,0,0,mPaint);//繪制目標圖形
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
        canvas.drawBitmap(srcBitmap,0,0,mPaint);//繪制源圖
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                mPath.moveTo(event.getX(),event.getY());
                firstDownX = event.getX();
                firstDownY = event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                float moveX = event.getX();
                float moveY = event.getY();
                float endX = (firstDownX+moveX)/2;
                float endY = (firstDownY+moveY)/2;
                mPath.quadTo(firstDownX,firstDownY,endX,endY);
                firstDownX = moveX;
                firstDownY =moveY;
                postInvalidate();
                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        return true;
    }
}
效果: \ 發現這和我們想要的橡皮擦效果不一樣,是的,只要在onDraw()方法最後加上這行代碼就ok了, mPaint.setXfermode(null); 效果: \ 上面的原理分析圖最後合拼的時候說錯了,說反了!     10:Mode.SRC_OVER 效果: \ 11:Mode.SRC_ATOP \ 12:Mode.DST 效果: \ 這個相當於源圖形是透明的, 13:Mode.DST_IN 效果: \
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved