Android Paint PorterDuffXfermode

Xfermode 还有一个子类 PorterDuffXfermode

PorterDuffXfermode(PorterDuff.Mode mode)
参数 说明
mode PorterDuff.Mode 图片混排模式

PorterDuff.Mode

PorterDuff.Mode 可以简单的理解为两个图层按照不同模式,可以组合成不同的结果显示出来

Android 提供了 18 种图片混排模式,这些混排模式会用到两个图层:先绘制的图是 目标图(DST) ,后绘制的图是 源图(SRC)

范例

我们写一个范例来演示各种模式


  1. 创建一个 空的 Android 项目 cn.twle.android.PorterDuffMode

  2. 自定义一个 View 类 XfermodeView.java

    获取了屏幕宽高,然后画了一个矩形一个圆形,计算了一下它们的位置,然后设置下图层,接着设下下画笔 setXfermode,最后绘制到 canvas 上

    package cn.twle.android.porterduffmode;
    
    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.util.DisplayMetrics;
    import android.util.Log;
    import android.view.View;
    import android.view.WindowManager;
    
    public class XfermodeView extends View {
    
        private Context context;
    
        //屏幕宽高
        private int screenW;
    
        //绘制的图片宽高
        private int width = 200;
        private int height = 200;
    
        //上层SRC的Bitmap和下层Dst的Bitmap
        private Bitmap srcBitmap, dstBitmap;
    
        public XfermodeView(Context context) {
            this(context, null);
        }
    
        public XfermodeView(Context context, AttributeSet attrs) {
            super(context, attrs);
    
            this.context = context;
    
            WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
            DisplayMetrics dm = new DisplayMetrics();
            manager.getDefaultDisplay().getMetrics(dm);
    
            screenW = dm.widthPixels;
    
            //实例化两个Bitmap
            srcBitmap = makeSrc(width, height);
            dstBitmap = makeDst(width, height);
        }
    
        public XfermodeView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        @Override
        public void onMeasure(int width,int height ) {
    
            WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
            DisplayMetrics dm = new DisplayMetrics();
            manager.getDefaultDisplay().getMetrics(dm);
    
            screenW = dm.widthPixels;
    
            setMeasuredDimension(screenW,8000);
        }
    
        //定义一个绘制圆形 Bitmap 的方法
        private Bitmap makeDst(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(0xFFE54261);
            c.drawOval(new RectF(0, 0, w * 3 / 4, h * 3 / 4), p);
            return bm;
        }
    
        //定义一个绘制矩形的 Bitmap 的方法
        private Bitmap makeSrc(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(0xFF3097F3);
            c.drawRect(w / 3, h / 3, w * 19 / 20, h * 19 / 20, p);
            return bm;
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            Paint paint = new Paint();
            paint.setFilterBitmap(false);
            paint.setStyle(Paint.Style.FILL);
            paint.setTextSize(48.0f);
    
            for ( PorterDuff.Mode mode : PorterDuff.Mode.class.getEnumConstants()) {
    
                Log.d("modes",mode.name());
                canvas.drawText(mode.name(), 10, 50, paint);
                canvas.drawBitmap(srcBitmap, (screenW / 3 - width) / 2, 100, paint);
                canvas.drawBitmap(dstBitmap, (screenW / 3 - width) / 2 + screenW / 3, 100, paint);
    
                int sc = canvas.saveLayer(0, 0, screenW, 300, null, Canvas.ALL_SAVE_FLAG);
    
                canvas.drawBitmap(dstBitmap, (screenW / 3 - width) / 2 + screenW / 3 * 2,
                        100, paint);     //绘制
    
                //设置Paint的Xfermode
                paint.setXfermode(new PorterDuffXfermode(mode));
                canvas.drawBitmap(srcBitmap, (screenW / 3 - width) / 2 + screenW / 3 * 2,
                        100, paint);
                paint.setXfermode(null);
    
                // 还原画布
                canvas.restoreToCount(sc);
    
                canvas.translate(0, 400);
    
            }
        }
    }
    
  3. 修改 MainActivity.java

    package cn.twle.android.porterduffmode;
    
    import android.graphics.PorterDuff;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            setContentView(R.layout.activity_main);
        }
    }
    

如果需要查看不同的模式,只要 XfermodeView 下面这条语句即可

private PorterDuff.Mode PD_MODE = PorterDuff.Mode.ADD;

PorterDuff.Mode.ADD

饱和度叠加

PorterDuff.Mode.CLEAR:

所绘制不会提交到画布上

PorterDuff.Mode.DARKEN

取两图层全部区域,交集部分颜色加深

PorterDuff.Mode.DST

只保留目标图的 alpha 和 color,所以绘制出来只有目标图

PorterDuff.Mode.DST_ATOP:

源图和目标图相交处绘制目标图,不相交的地方绘制源图

PorterDuff.Mode.DST_IN

两者相交的地方绘制目标图,绘制的效果会受到原图处的透明度影响

PorterDuff.Mode.DST_OUT

在不相交的地方绘制目标图

PorterDuff.Mode.DST_OVER

目标图绘制在上方

PorterDuff.Mode.LIGHTEN

取两图层全部区域,点亮交集部分颜色

PorterDuff.Mode.MULTIPLY

取两图层交集部分叠加后颜色

PorterDuff.Mode.OVERLAY

叠加

PorterDuff.Mode.SCREEN

取两图层全部区域,交集部分变为透明色

PorterDuff.Mode.SRC

只保留源图像的 alpha 和 color,所以绘制出来只有源图

PorterDuff.Mode.SRC_ATOP

源图和目标图相交处绘制源图,不相交的地方绘制目标图

PorterDuff.Mode.SRC_IN

两者相交的地方绘制源图

PorterDuff.Mode.SRC_OUT

不相交的地方绘制源图

PorterDuff.Mode.SRC_OVER

把源图绘制在上方

PorterDuff.Mode.XOR

不相交的地方按原样绘制源图和目标图

参考文档

  1. Android PorterDuffXfermode

Android 基础教程

关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.