赞
踩
- setXfermode(Xfermode xfermode)
-
- @param xfermode May be null. The xfermode to be installed in the paint
-
- 译文:xfermode 可以为空,并且必须安装到画笔上
-
- Xfermode对象由 PorterDuffXfermode(PorterDuff.Mode mode)构造方法产生
-
- PorterDuff.Mode mode 有18种
-
-
- 使用步骤:
-
- 第一步:绘制 目标(dst)图
- 第二步: 给 画笔 设置模式
- 第三步:绘制 源 (src) 图
- 第四步:清除 画笔 模式
-
- 注意: 绘制 dst 和 src 的时候要指定画笔 并且是设置了模式的同一个画笔

有兄弟说上面只有16种,对,说明你数学很好。
还有两种是 新增的,分别为 ADD和OVERLAY两种模式
饱和度叠加
清除
取两图层全部区域,交集部分颜色加深
只保留目标图的alpha和color,所以绘制出来只有目标图
源图和目标图相交处绘制目标图,不相交的地方绘制源图
两者相交的地方绘制目标图,绘制的效果会受到原图处的透明度影响
在不相交的地方绘制目标图
目标图绘制在上方
取两图层全部区域,点亮交集部分颜色
取两图层交集部分叠加后颜色
叠加
取两图层全部区域,交集部分变为透明色
只保留源图像的alpha和color,所以绘制出来只有源图
源图和目标图相交处绘制源图,不相交的地方绘制目标图
两者相交的地方绘制源图
不相交的地方绘制源图
把源图绘制在上方
不相交的地方按原样绘制源图和目标图
自定义布局java代码
- package com.wust.xfmode;
-
- 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.view.View;
-
- import androidx.annotation.Nullable;
-
- /**
- * ClassName: MyXfModeView <br/>
- * Description: <br/>
- * date: 2021/8/9 17:29<br/>
- *
- * @author yiqi<br />
- * @QQ 1820762465
- * @微信 yiqiideallife
- * @技术交流QQ群 928023749
- */
- public class MyXfModeView extends View {
-
- private Paint paint;
- private Bitmap bitmap;
- //定义模式
- private PorterDuffXfermode pdXfermode;
- private Bitmap dstBm;
- private Bitmap srcBm;
- private int screenWidth;
- private int screenHeight;
- //定义模式 Array
- private PorterDuff.Mode[] modes = {
- PorterDuff.Mode.ADD,PorterDuff.Mode.CLEAR,PorterDuff.Mode.DARKEN,PorterDuff.Mode.DST,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,PorterDuff.Mode.SRC_ATOP,PorterDuff.Mode.SRC_IN,
- PorterDuff.Mode.SRC_OUT,PorterDuff.Mode.SRC_OVER,PorterDuff.Mode.XOR
- };
- private int mCurMode = 0;
-
- public MyXfModeView(Context context) {
- super(context);
- }
-
- public MyXfModeView(Context context, @Nullable AttributeSet attrs) {
- super(context, attrs);
- initPaint();
- initData();
- }
-
- public MyXfModeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- initPaint();
- initData();
- }
-
- private void initData() {
- //获取屏幕宽高
- DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
- screenWidth = displayMetrics.widthPixels;
- screenHeight = displayMetrics.heightPixels;
- //获取两张 bm 图
- dstBm = makeDst(screenWidth, screenHeight);
- srcBm = makeSrc(screenWidth, screenHeight);
- }
-
- private void initPaint() {
- paint = new Paint();
- paint.setAntiAlias(true);
- paint.setDither(true);
- paint.setStyle(Paint.Style.FILL);
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- //绘制圆图形
- canvas.drawBitmap(dstBm,0,0,null);
- canvas.drawBitmap(srcBm,0,0,null);
- //绘制分界线
- canvas.drawLine(0,screenHeight*2/4,screenWidth,screenHeight*2/4,paint);
- //创建图层 sc保存着创建图层前的画布状态
- RectF bounds = new RectF(0,screenHeight/2,screenWidth,screenHeight);
- int sc = canvas.saveLayer(bounds, null);
- //必须先 绘制 目标 bm
- canvas.drawBitmap(dstBm,0,screenHeight/2,paint);
- //然后 设置模式
- pdXfermode = new PorterDuffXfermode(modes[mCurMode]);
- paint.setXfermode(pdXfermode);
- //绘制 目标 bm
- canvas.drawBitmap(srcBm,0,screenHeight/2,paint);
- //一定要记得 模式用完之后去除
- paint.setXfermode(null);
- canvas.restoreToCount(sc);
-
- }
-
- //创建目标 bm 圆形
- private Bitmap makeDst(int w,int h){
- Bitmap bitmap = Bitmap.createBitmap(w,h, Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
- Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
- p.setColor(0xFF26AAD1);
- canvas.drawOval(w * 1 / 4, w * 1 / 4,w * 1 / 2, w * 1 / 2,p);
- return bitmap;
- }
-
- //创建源 bm 矩形
- private Bitmap makeSrc(int w,int h){
- Bitmap bitmap = Bitmap.createBitmap(w,h, Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
- Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
- p.setColor(0xFFFFCE43);
- canvas.drawRect(w *3/ 8, w *3/ 8, w * 5/8, w *5/8, p);
- return bitmap;
- }
-
- //暴露设置模式的方法
- public void setMode(int mode){
- this.mCurMode = mode;
- invalidate();
- }
- }

xml布局代码
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context=".MainActivity">
-
- <TextView
- android:id="@+id/tv_dscript"
- android:layout_centerInParent="true"
- android:layout_width="match_parent"
- android:layout_height="180dp"
- android:paddingTop="90dp"
- android:textColor="#F15A5A"
- android:gravity="center"/>
-
- <com.wust.xfmode.MyXfModeView
- android:id="@+id/mxmv_xfmode"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/>
-
- </RelativeLayout>

MainActivity.java
- package com.wust.xfmode;
-
- import androidx.annotation.NonNull;
- import androidx.appcompat.app.AppCompatActivity;
-
- import android.os.Bundle;
- import android.util.DisplayMetrics;
- import android.view.Menu;
- import android.view.MenuItem;
- import android.view.View;
- import android.view.WindowManager;
- import android.widget.TextView;
-
- public class MainActivity extends AppCompatActivity {
-
- private MyXfModeView mxmv_xfmode;
- private TextView tv_dscript;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- bindView();
- bindData();
- }
-
- private void bindData() {
-
- }
-
- private void bindView() {
- mxmv_xfmode = findViewById(R.id.mxmv_xfmode);
- tv_dscript = findViewById(R.id.tv_dscript);
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.mode_menu,menu);
- return super.onCreateOptionsMenu(menu);
- }
-
- @Override
- public boolean onOptionsItemSelected(@NonNull MenuItem item) {
- switch (item.getItemId()){
- case R.id.menu_add:
- {
- mxmv_xfmode.setMode(0);
- tv_dscript.setText("PorterDuff.Mode.ADD:饱和度叠加");
- }
- break;
- case R.id.menu_clear:
- {
- mxmv_xfmode.setMode(1);
- tv_dscript.setText("PorterDuff.Mode.CLEAR:清除");
- }
- break;
- case R.id.menu_darken:
- {
- mxmv_xfmode.setMode(2);
- tv_dscript.setText("PorterDuff.Mode.DARKEN:取两图层全部区域,交集部分颜色加深");
- }
- break;
- case R.id.menu_dst:
- {
- mxmv_xfmode.setMode(3);
- tv_dscript.setText("PorterDuff.Mode.DST:只保留目标图的alpha和color,所以绘制出来只有目标图");
- }
- break;
- case R.id.menu_dst_atop:
- {
- mxmv_xfmode.setMode(4);
- tv_dscript.setText("PorterDuff.Mode.DST_ATOP:源图和目标图相交处绘制目标图,不相交的地方绘制源图");
- }
- break;
- case R.id.menu_dst_in:
- {
- mxmv_xfmode.setMode(5);
- tv_dscript.setText("PorterDuff.Mode.DST_IN:两者相交的地方绘制目标图,绘制的效果会受到原图处的透明度影响");
- }
- break;
- case R.id.menu_dst_out:
- {
- mxmv_xfmode.setMode(6);
- tv_dscript.setText("PorterDuff.Mode.DST_OUT:在不相交的地方绘制目标图");
- }
- break;
- case R.id.menu_dst_over:
- {
- mxmv_xfmode.setMode(7);
- tv_dscript.setText("PorterDuff.Mode.DST_OVER:目标图绘制在上方");
- }
- break;
- case R.id.menu_lighten:
- {
- mxmv_xfmode.setMode(8);
- tv_dscript.setText("PorterDuff.Mode.LIGHTEN:取两图层全部区域,点亮交集部分颜色");
- }
- break;
- case R.id.menu_multiply:
- {
- mxmv_xfmode.setMode(9);
- tv_dscript.setText("PorterDuff.Mode.MULTIPLY:取两图层交集部分叠加后颜色");
- }
- break;
- case R.id.menu_overlay:
- {
- mxmv_xfmode.setMode(10);
- tv_dscript.setText("PorterDuff.Mode.OVERLAY:叠加");
- }
- break;
- case R.id.menu_screen:
- {
- mxmv_xfmode.setMode(11);
- tv_dscript.setText("PorterDuff.Mode.SCREEN:取两图层全部区域,交集部分变为透明色");
- }
- break;
- case R.id.menu_src:
- {
- mxmv_xfmode.setMode(12);
- tv_dscript.setText("PorterDuff.Mode.SRC:只保留源图像的alpha和color,所以绘制出来只有源图");
- }
- break;
- case R.id.menu_src_atop:
- {
- mxmv_xfmode.setMode(13);
- tv_dscript.setText("PorterDuff.Mode.SRC_ATOP:源图和目标图相交处绘制源图,不相交的地方绘制目标图");
- }
- break;
- case R.id.menu_src_in:
- {
- mxmv_xfmode.setMode(14);
- tv_dscript.setText("PorterDuff.Mode.SRC_IN:两者相交的地方绘制源图");
- }
- break;
- case R.id.menu_src_out:
- {
- mxmv_xfmode.setMode(15);
- tv_dscript.setText("PorterDuff.Mode.SRC_OUT:不相交的地方绘制源图");
- }
- break;
- case R.id.menu_src_over:
- {
- mxmv_xfmode.setMode(16);
- tv_dscript.setText("PorterDuff.Mode.SRC_OVER:把源图绘制在上方");
- }
- break;
- case R.id.menu_xor:
- {
- mxmv_xfmode.setMode(17);
- tv_dscript.setText("PorterDuff.Mode.XOR:不相交的地方按原样绘制源图和目标图");
- }
- break;
- }
- return super.onOptionsItemSelected(item);
- }
- }

menu.xml
- <?xml version="1.0" encoding="utf-8"?>
- <menu xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:id="@+id/menu_add" android:title="PorterDuff.Mode.ADD"/>
- <item android:id="@+id/menu_clear" android:title="PorterDuff.Mode.CLEAR"/>
- <item android:id="@+id/menu_darken" android:title="PorterDuff.Mode.DARKEN"/>
- <item android:id="@+id/menu_dst" android:title="PorterDuff.Mode.DST"/>
- <item android:id="@+id/menu_dst_atop" android:title="PorterDuff.Mode.DST_ATOP"/>
- <item android:id="@+id/menu_dst_in" android:title="PorterDuff.Mode.DST_IN"/>
- <item android:id="@+id/menu_dst_out" android:title="PorterDuff.Mode.DST_OUT"/>
- <item android:id="@+id/menu_dst_over" android:title="PorterDuff.Mode.DST_OVER"/>
- <item android:id="@+id/menu_lighten" android:title="PorterDuff.Mode.LIGHTEN"/>
- <item android:id="@+id/menu_multiply" android:title="PorterDuff.Mode.MULTIPLY"/>
- <item android:id="@+id/menu_overlay" android:title="PorterDuff.Mode.OVERLAY"/>
- <item android:id="@+id/menu_screen" android:title="PorterDuff.Mode.SCREEN"/>
- <item android:id="@+id/menu_src" android:title="PorterDuff.Mode.SRC"/>
- <item android:id="@+id/menu_src_atop" android:title="PorterDuff.Mode.SRC_ATOP"/>
- <item android:id="@+id/menu_src_in" android:title="PorterDuff.Mode.SRC_IN"/>
- <item android:id="@+id/menu_src_out" android:title="PorterDuff.Mode.SRC_OUT"/>
- <item android:id="@+id/menu_src_over" android:title="PorterDuff.Mode.SRC_OVER"/>
- <item android:id="@+id/menu_xor" android:title="PorterDuff.Mode.XOR"/>
- </menu>

你在绘制的过程中可能会发现与预期结果不一样,如下:
错误图
正确图
其中的解决方法有两种:
1、给画布添加背景
2、添加图层
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。