Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android遮罩Xfermode的學習

android遮罩Xfermode的學習

編輯:關於Android編程

先看看效果吧
效果

根據官方APIDemo給出的Xfermode例子我們可以看到下圖展示那樣
demo

但是,說實話,看到這張圖,我是懵逼的,我們應該去自己試一試來加深下自己的理解,所以我畫了下,得到的結果如下,僅供參考!最好自己試一試

我先畫的正方形,後畫的圓
s

//        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); //圓和正方形相交部分清除,圓與透明部分相交也清除
//        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)); //覆蓋在表面,相交部分正方形被清除,圓與透明相交不被清除
//        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST)); //清除覆蓋在上面的圓,圓相交不相交部分都清除
//        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));//圓覆蓋在表面,正方形內部沒影響,圓與透明相交不被清除
//        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OVER));//清除覆蓋在上面的圓,圓與透明部分相交不清除
//        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));//顯示相交的,覆蓋在上面的圓,清除不相交部分的圓和相交部分的正方形
//        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));//圓被清除,相交部分隨著圓的透明度變化而正比例變化
//        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));//清除相交部分的圓和正方形,不相交不清除
//        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));//圓被清除,相交部分隨著圓的透明度變化而反比例
//        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));//顯示相交的,覆蓋在上面的圓,清除不相交部分的圓不清除相交部分的正方形,和SRC_IN對比
//        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP));//相交部分圓被清除,相交部分隨著圓的透明度變化而正比例變化,與DST_IN對比
//        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR));//相交部分圓被清除,相交部分隨著圓的透明度變化而反比例變化
//        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DARKEN));//相交部分加黑色素,透明度越大,越黑
//        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN));//相交部分加亮色素,透明度越大,越亮
//        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));//相交部分加黑色素,透明度越大,越黑,圓不相交部分被清除
//        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN));//相交部分加亮色素,透明度越大,越亮,感覺和LIGHTEN 一樣

僅供參考,最好自己試一試。

弄清楚各遮罩的效果,就可以開始做了,這裡面,實現圓形頭像我使用的是PorterDuff.Mode.SRC_IN

//顯示相交的,覆蓋在上面的圓,清除不相交部分的圓和相交部分的正方形

嗯,這可以先畫一個實心圓,然後在把背景圖片畫上去,PorterDuff.Mode.SRC_IN會清除不相交部分的背景圖,所以就只剩下相交部分的圓形背景圖了,這樣就實現了。原理就是這樣,我們來看看實際怎麼實現吧

/**
 * Created by Administrator on 2016/10/16 0016.
 */

public class CircleView extends View {

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

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

    @Override
    public void draw(Canvas canvas) { //重寫view的draw方法,view繪制的時候會調用此方法

        Bitmap bitmap = Bitmap.createBitmap(getWidth(),getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas1 = new Canvas(bitmap); //bitmap為畫紙,canvas1是畫板
        super.draw(canvas1); //把背景圖畫在canvas1這張畫板上,但注意畫是畫在紙上的,即背景圖在bitmap上

        Bitmap bitmap2 = Bitmap.createBitmap(bitmap.getWidth(),bitmap.getHeight(), Bitmap.Config.ARGB_8888);//注意這裡要帶A即支持透明
        Canvas canvas2 = new Canvas(bitmap2); //再來一張新畫紙,新畫板

        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setColor(Color.WHITE);
        canvas2.drawARGB(0,0,0,0);   //初始化畫紙帶透明

        //畫實心圓 paint的style默認是fill填充的
        canvas2.drawCircle(bitmap.getWidth()/2,bitmap.getHeight()/2,bitmap.getWidth()/2,paint);

        //設置遮罩的模式
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));

        //前面我們已經通過super.draw(canvas1);把背景都畫在了畫紙bitmap上,即此時畫背景即是畫bitmap
        canvas2.drawBitmap(bitmap,0,0,paint);//此時,其實我們想要的效果就得到了,但是如果就這麼結束的話,
        //是不行的,因為我們畫在canvas2畫板上!!!而view要顯示是要畫在,它自己帶的參數canvas畫板上的!!!

        //所以我們這裡把canvas2畫板上的畫紙bitmap2畫上來,這樣view就達到我們想要的效果了
        canvas.drawBitmap(bitmap2,0,0,null);

        addStroke(canvas);

    }

    /**增加描邊*/
    private void addStroke(Canvas canvas) {
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStrokeWidth(2);
        paint.setColor(Color.RED);
        paint.setStyle(Paint.Style.STROKE);
        canvas.drawCircle(getWidth() / 2, getHeight() / 2,
                (float) (getHeight() / 2 -1), paint);
    }
}

布局

我注釋寫的還算詳細吧,跟著注釋跟著代碼一起讀覺得比較好理解.

接下來的微信效果其實也是大巫小巫的問題,不是問題,這裡用的是PorterDuff.Mode.SRC_ATOP

//顯示相交的,覆蓋在上面的圓,清除不相交部分的圓不清除相交部分的正方形,和SRC_IN對比

它與SRC_IN不同的就是他不會清除相交部分 覆蓋在下面的圖形,然後我們改變上面的透明度就行了。選來看看那個圖標
s

格子表示透明,好吧,中間那坨本來也是透明的,是我塗的白色,這裡推薦一個阿裡的圖標網站http://www.iconfont.cn/,真的很好,雷鋒啊。嗯,原理是這樣,來看看怎麼實現吧

public class GradientView extends View{
    public GradientView(Context context) {
        this(context,null);
    }

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

    int alpha = 255;
    public GradientView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        final Timer timer = new Timer();
        TimerTask task = new TimerTask() {
            @Override
            public void run() {

                alpha -= 10;      //每300毫秒背景色越透明
                if (alpha < 0){
                    timer.cancel();

                }else{
                    postInvalidate(); //主動調draw方法刷新視圖
                }


            }
        };
        timer.schedule(task,1000,300);
    }

    public Bitmap icon;

    public  void setBitmap(Bitmap bitmap){
        icon = bitmap;  //外部傳圖標
        postInvalidate();//主動調draw方法刷新視圖
    }

    private String txt;
    public  void setText(String text){
        txt = text;    //外部傳文字
        postInvalidate();//主動調draw方法刷新視圖
    }


    @Override
    public void draw(Canvas canvas) {  //與上面的實現圓形頭像一樣,只是換了個遮罩模式

        Bitmap bitmap = Bitmap.createBitmap(getWidth(),getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas1 = new Canvas(bitmap);
        super.draw(canvas1);   //背景色畫在bitmap上

        Bitmap bitmap1 = Bitmap.createBitmap(bitmap.getWidth(),bitmap.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas2 = new Canvas(bitmap1);

        canvas2.drawARGB(0,0,0,0);
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setTextAlign(Paint.Align.CENTER);
        paint.setTextSize(13);
        paint.setColor(Color.BLACK);

        if(txt != null){ //畫文字
            canvas2.drawText(txt,getWidth()/2,getHeight()-5,paint);
        }


        if(icon != null){ //畫圖片

            Matrix matrix = new Matrix(); //幫助實現bitmap縮放

            matrix.postScale(getWidth()/3.0f/icon.getWidth(),getWidth()/3.0f/icon.getHeight());
            canvas2.drawBitmap(Bitmap.createBitmap(icon,0,0,icon.getWidth(),icon.getHeight(),matrix,true),getWidth()/3,0,null);
        }


        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));

        paint.setAlpha(alpha); //透明度變化
        canvas2.drawBitmap(bitmap,0,0,paint);  //將背景色畫在圖標和文字上面,相交的部分才顯示

        canvas.drawBitmap(bitmap1,0,0,null);  //最後畫在畫板上,不理解回去看圓形圖片實現

        //四周的邊框
        Paint paint1 = new Paint();
        paint1.setColor(Color.RED);
        paint.setAntiAlias(true);
        paint1.setStyle(Paint.Style.STROKE);
        canvas.drawRect(0,0,getWidth(),getHeight(),paint1);
    }
}
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_circle);

        GradientView gv = (GradientView) findViewById(R.id.gv);
        gv.setBitmap(BitmapFactory.decodeResource(getResources(),R.mipmap.weixin_logo));
        gv.setText("微信");
    }

最重要的還是知道了各種遮罩的特性,有時間自己最好試一下,下次就用這個GradientView來實現微信的底部導航菜單吧

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved