深入理解Android绘图中的PorterDuffXfermode
前言
本人现在是一名大三的实习生,最近导师让我就实习所收获到的知识记录下来并进行分享,我就想能不能用CSDN博客的形式进行记录,而且通过写博客的形式我也会对这些知识有更加深入的理解,但这是我一次写博客,有很多地方不是很熟悉,大家就凑合着看吧!!好了回到正题!
概要
今天的主角是android.graphics.PorterDuffXfermode
,它是android.graphics.Xfermode
的子类,Xfermode一共有3个子类,分别是AvoidXfermode、PixelXorXfermode和PorterDuffXfermode,但是前两个都在API 16之后被标记为removed了,所以我们重点讲解PorterDuffXfermode。当我们用paint.setXfermode(Xfermode xfermode)
向画笔设置指定的模式时 ,Android会根据不同的模式采取不同的规则把源像素(SRC) 和目标像素(DST) 进行混合,从而实现不同的效果。Android提供了16种模式,分别是:CLEAR、SRC、DST、SRC_OVER、DST_OVER、SRC_IN、DST_IN、SRC_OUT、DST_OUT、SRC_ATOP、DST_ATOP、XOR、DARKEN、LIGHTEN、MULTIPLY、SCREEN。当我们不需要设置模式的时候可以用paint.setXfermode(null)
。
混合规则(规则都可以在源码中找到)
模式 | 规则 |
---|---|
CLEAR | [0,0] |
SRC | [Sa,Sc] |
DST | [Da,Dc] |
SRC_OVER | [Sa + (1 - Sa)*Da,Sc + (1 - Sa)*Dc] |
DST_OVER | [Da + (1 - Da)*Sa,Dc + (1 - Dc)*Sc] |
SRC_IN | [Sa* Da, Sc* Da] |
DST_IN | [Sa* Da, Sa* Dc] |
SRC_OUT | [(1 - Da)* Sa,(1 - Da)* Sc] |
DST_OUT | [(1 - Sa)* Da,(1-Sa)* Dc] |
SRC_ATOP | [Da,Da* Sc + (1 - Sa)* Dc] |
DST_ATOP | [Sa,Sa* Dc + (1 - Da)* Sc] |
XOR | [(1-Da)* Sa + (1-Sa)* Da,(1-Da)Sc + (1-Sa) Dc] |
DARKEN | [Sa+Da-Sa*Da,(1-Da)*Sc + (1-Sa)*Dc + min(Sc,Dc)] |
LIGHTEN | [Sa+Da-Sa* Da,(1-Da)*Sc + (1-Sa)*Dc + max(Sc,Dc)] |
MULTIPLY | [Sa+Da-SaDa,Sc+Dc-ScDc] |
SCREEN | [max(0,min(Sa+Da,1)),max(0,min(Sc+Dc,1))] |
名词解释
[alpha,color],指的是按规则混合后最终输出像素的透明度和颜色值
a—alpha,指透明度
c—color,指颜色值
S—SRC,源像素
D—DST,目标图像
Sa,即源像素的透明度,Sc指源像素的颜色值,依此类推…
那问题来了,源像素和目标像素到底是什么?下面我将分析不同的示例,尽可能让大家理解。
示例一(不设置Xfermode)
先贴上全部代码(后面只贴关键部分)
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
>
<com.example.xfermodedemo.view.PorterDuffXfermodeTestView
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity
package com.example.xfermodedemo;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
public class