在必要时候需要弯一弯,转一转,因为太坚强容易折断,我们需要更多的柔软,才能战胜挫折。
本讲内容:PorterDuffXfermode图形混合模式类(只有一个含参的构造方法)
<span style="font-size:18px;">PorterDuffXfermode(PorterDuff.Mode mode)</span>
在API中Android为我们提供了的18种图形混合模式:
Sa全称为Source alpha表示源图的Alpha通道;Sc全称为Source color表示源图的颜色;Da全称为Destination alpha表示目标图的Alpha通道;Dc全称为Destination color表示目标图的颜色
比上图多了少种ADD和OVERLAY)模式:(上层( src源图 )、下层(dis目标图) )
1、PorterDuff.Mode.CLEAR 所绘制不会提交到画布上。
2、PorterDuff.Mode.SRC 显示上层绘制图片
3、PorterDuff.Mode.DST 显示下层绘制图片
4、PorterDuff.Mode.SRC_OVER 正常绘制显示,上下层绘制叠盖。
5、PorterDuff.Mode.DST_OVER 上下层都显示。下层居上显示。
6、PorterDuff.Mode.SRC_IN 取两层绘制交集。显示上层。
7、PorterDuff.Mode.DST_IN 取两层绘制交集。显示下层。
8、PorterDuff.Mode.SRC_OUT 取上层绘制非交集部分。
9、PorterDuff.Mode.DST_OUT 取下层绘制非交集部分。
10、PorterDuff.Mode.SRC_ATOP 取下层非交集部分与上层交集部分
11、PorterDuff.Mode.DST_ATOP 取上层非交集部分与下层交集部分
12.PorterDuff.Mode.XOR 取两层绘制非交集。两层绘制非交集。
13、PorterDuff.Mode.DARKEN 上下层都显示。变暗
14、PorterDuff.Mode.LIGHTEN 上下层都显示。变量
15、PorterDuff.Mode.MULTIPLY 取两层绘制交集
16、PorterDuff.Mode.SCREEN 上下层都显示。
17、PorterDuff.Mode.ADD 上下层饱和度相加
18、PorterDuff.Mode.OVERLAY 上下层叠加
示例一:DST_IN 取两层绘制交集。显示下层。
dis目标图 src源图 混合模式效果图(文字不见了)
下面是自定义CustomTitleView.java文件:
public class CustomView extends View { private Paint mPaint;// 画笔 private Bitmap bitmapDis, bitmapSrc;// 位图 private PorterDuffXfermode porterDuffXfermode;// 图形混合模式 private int x, y;// 位图绘制时左上角的起点坐标 private int screenW, screenH;// 屏幕尺寸 public CustomView(Context context) { super(context, null); } public CustomView(Context context, AttributeSet attrs) { super(context, attrs); // 实例化混合模式 porterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN); // 初始化画笔 initPaint(); // 初始化资源 initRes(context); } // 初始化画笔 private void initPaint() { // 实例化画笔并打开抗锯齿 mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); } // 初始化资源 private void initRes(Context context) { // 获取位图 bitmapDis = BitmapFactory.decodeResource(context.getResources(), R.drawable.a1); bitmapSrc = BitmapFactory.decodeResource(context.getResources(), R.drawable.a2); // 获取包含屏幕尺寸的数组 int[] screenSize = MeasureUtil.getScreenSize((Activity) context); // 获取屏幕尺寸 screenW = screenSize[0]; screenH = screenSize[1]; /* * 计算位图绘制时左上角的坐标使其位于屏幕中心 * 屏幕坐标x轴向左偏移位图一半的宽度 * 屏幕坐标y轴向上偏移位图一半的高度 */ x = screenW / 2 - bitmapDis.getWidth() / 2; y = screenH / 2 - bitmapDis.getHeight() / 2; } protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.WHITE); // 将绘制操作保存到新的图层(离屏缓存) int sc = canvas.saveLayer(0, 0, screenW, screenH, null, Canvas.ALL_SAVE_FLAG); // 先绘制dis目标图 canvas.drawBitmap(bitmapDis, x, y, mPaint); // 设置混合模式 mPaint.setXfermode(porterDuffXfermode); // 再绘制src源图 canvas.drawBitmap(bitmapSrc, x, y, mPaint); // 还原混合模式 mPaint.setXfermode(null); // 还原画布 canvas.restoreToCount(sc); }}
示例二:DST_OUT 取下层绘制非交集部分。
src源图 效果图
下面是自定义CustomTitleView.java文件:
public class CustomView extends View { private Paint mPaint;// 画笔 private Bitmap bitmapSrc;// 位图 private PorterDuffXfermode porterDuffXfermode;// 图形混合模式 private int x, y;// 位图绘制时左上角的起点坐标 private int screenW, screenH;// 屏幕尺寸 public CustomView(Context context) { super(context, null); } public CustomView(Context context, AttributeSet attrs) { super(context, attrs); // 实例化混合模式 porterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT); // 初始化画笔 initPaint(); // 初始化资源 initRes(context); } // 初始化画笔 private void initPaint() { // 实例化画笔并打开抗锯齿 mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); } // 初始化资源 private void initRes(Context context) { // 获取位图 bitmapSrc = BitmapFactory.decodeResource(context.getResources(),R.drawable.c5); // 获取包含屏幕尺寸的数组 int[] screenSize = MeasureUtil.getScreenSize((Activity) context); // 获取屏幕尺寸 screenW = screenSize[0]; screenH = screenSize[1]; /* * 计算位图绘制时左上角的坐标使其位于屏幕中心 * 屏幕坐标x轴向左偏移位图一半的宽度 * 屏幕坐标y轴向上偏移位图一半的高度 */ x = screenW / 2 - bitmapSrc.getWidth() / 2; y = screenH / 2 - bitmapSrc.getHeight() / 2; } protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.WHITE); // 将绘制操作保存到新的图层(离屏缓存) int sc = canvas.saveLayer(0, 0, screenW, screenH, null, Canvas.ALL_SAVE_FLAG); // 先绘制一层颜色(先绘制dis目标图) canvas.drawColor(0xFFFF04DA); // 设置混合模式 mPaint.setXfermode(porterDuffXfermode); // 再绘制src源图 canvas.drawBitmap(bitmapSrc, x, y, mPaint); // 还原混合模式 mPaint.setXfermode(null); // 还原画布 canvas.restoreToCount(sc); }}
示例三:橡皮檫效果
我们可以通过手指不断地触摸屏幕绘制Path,再以Path作遮罩遮掉填充的色块显示下层的图像:
public class CustomView extends View { // 最小的移动距离:如果我们手指在屏幕上的移动距离小于此值则不会绘制 private static final int MIN_MOVE_DIS = 5; private Bitmap fgBitmap, bgBitmap;// 前景橡皮擦的Bitmap和背景我们底图的Bitmap private Canvas mCanvas;// 绘制橡皮擦路径的画布 private Paint mPaint;// 橡皮檫路径画笔 private Path mPath;// 橡皮擦绘制路径 private int screenW, screenH;// 屏幕宽高 private float preX, preY;// 记录上一个触摸事件的位置坐标 public CustomView(Context context) { super(context, null); } public CustomView(Context context, AttributeSet attrs) { super(context, attrs); // 计算参数 cal(context); // 初始化对象 init(context); } // 计算参数 private void cal(Context context) { // 获取屏幕尺寸数组 int[] screenSize = MeasureUtil.getScreenSize((Activity) context); // 获取屏幕宽高 screenW = screenSize[0]; screenH = screenSize[1]; } // 初始化对象 private void init(Context context) { // 实例化路径对象 mPath = new Path(); // 实例化画笔并开启其抗锯齿和抗抖动 mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); // 设置画笔透明度为0是关键!我们要让绘制的路径是透明的,然后让该路径与前景的底色混合“抠”出绘制路径 mPaint.setARGB(128, 255, 0, 0); // 设置混合模式为DST_IN mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); // 设置画笔风格为描边 mPaint.setStyle(Paint.Style.STROKE); // 设置路径结合处样式 mPaint.setStrokeJoin(Paint.Join.ROUND); // 设置笔触类型 mPaint.setStrokeCap(Paint.Cap.ROUND); // 设置描边宽度 mPaint.setStrokeWidth(50); // 生成前景图Bitmap fgBitmap = Bitmap.createBitmap(screenW, screenH, Config.ARGB_8888); // 将其注入画布 mCanvas = new Canvas(fgBitmap); // 绘制画布背景为中性灰 mCanvas.drawColor(0xFF808080); // 获取背景底图Bitmap bgBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.a4); // 缩放背景底图Bitmap至屏幕大小 bgBitmap = Bitmap.createScaledBitmap(bgBitmap, screenW, screenH, true); } protected void onDraw(Canvas canvas) { // 绘制背景 canvas.drawBitmap(bgBitmap, 0, 0, null); // 绘制前景 canvas.drawBitmap(fgBitmap, 0, 0, null); /* * 这里要注意canvas和mCanvas是两个不同的画布对象 * 当我们在屏幕上移动手指绘制路径时会把路径通过mCanvas绘制到fgBitmap上 * 每当我们手指移动一次均会将路径mPath作为目标图像绘制到mCanvas上,而在上面我们 先在mCanvas上绘制了中性灰色 * 两者会因为DST_IN模式的计算只显示中性灰,但是因为mPath的透明,计算生成的混合 图像也会是透明的 所以我们会得到“橡皮擦”的效果 */ mCanvas.drawPath(mPath, mPaint); } //View的事件 public boolean onTouchEvent(MotionEvent event) { //获取当前事件位置坐标 float x = event.getX(); float y = event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN:// 手指接触屏幕重置路径 mPath.reset(); mPath.moveTo(x, y); preX = x; preY = y; break; case MotionEvent.ACTION_MOVE:// 手指移动时连接路径 float dx = Math.abs(x - preX); float dy = Math.abs(y - preY); if (dx >= MIN_MOVE_DIS || dy >= MIN_MOVE_DIS) { mPath.quadTo(preX, preY, (x + preX) / 2, (y + preY) / 2); preX = x; preY = y; } break; } // 重绘视图 invalidate(); return true; } }
Take your time and enjoy it 路过的、学习过的请留个言,顶个呗~~