// 设置绘制路径的效果,如点画线等
PathEffect setPathEffect(PathEffect effect);
// 设置MaskFilter,可以用不同的MaskFilter实现滤镜的效果,如滤化,立体等
MaskFilter setMaskFilter(MaskFilter maskfilter);
// 设置Typeface对象,即字体风格,包括粗体,斜体以及衬线体,非衬线体等
Typeface setTypeface(Typeface typeface);
// 设置光栅化
Rasterizer setRasterizer(Rasterizer rasterizer);
// 在图形下面设置阴影层,产生阴影效果,radius为阴影的角度,dx和dy为阴影在x轴和y轴上的距离,color为阴影的颜色
// 注意:在Android4.0以上默认开启硬件加速,有些图形的阴影无法显示。关闭View的硬件加速 view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
void setShadowLayer(float radius, float dx, float dy, int color);
// 设置文本对齐
void setTextAlign(Align align);
// 设置字体大小
void setTextSize(float textSize);
// 设置文本缩放倍数,1.0f为原始
void setTextScaleX(float scaleX);
// 设置斜体文字,skewX为倾斜弧度
void setTextSkewX(float skewX);
复制代码
Paint 高级使用
渲染
1. 绘制图像阴影效果 setShadowLayer
val paint = Paint()
paint.setStyle(Paint.Style.FILL)
paint.setColor(Color.BLACK)
// 设置透明度,要在setColor后面设置才生效
paint.setAlpha(80)
// 如果不关闭硬件加速,setShadowLayer无效
setLayerType(View.LAYER_TYPE_SOFTWARE, null)
// (阴影的半径,X轴方向上相对主体的位移,Y轴相对位移)
paint.setShadowLayer(50f, 10f, 10f, Color.RED)
paint.setTextSize(50f)
// cx和cy为圆点的坐标
val radius = 200
val offest = 40
val startX = width / 2 - radius
val startY = height / 2
canvas.drawText(“画一个圆”, width / 2 - 100f, height / 2f - 300, paint)
canvas.drawCircle(startX.toFloat(), startY.toFloat(), radius.toFloat(), paint)
paint.setStyle(Paint.Style.STROKE)
paint.setStrokeWidth(5f)
paint.setShadowLayer(50f, -20f, 10f, Color.RED)
canvas.drawCircle(startX + radius * 2 + offest.toFloat(), startY.toFloat(), radius.toFloat(), paint)
复制代码

2. 为 Bitmap 设置图形渲染 BitmapShader

class MyGradientView : View {
private var mPaint: Paint? = null
private var mBitMap: Bitmap? = null
private var mWidth: Int = 0
private var mHeight: Int = 0
private val mColors = intArrayOf(Color.RED, Color.GREEN, Color.BLUE, Color.YELLOW)
constructor(context: Context?) : super(context) {
init()
}
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {
init()
}
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
private fun init() {
mBitMap = (resources.getDrawable(R.mipmap.girl_gaitubao) as BitmapDrawable).bitmap
mPaint = Paint()
mWidth = mBitMap!!.getWidth()
mHeight = mBitMap!!.getHeight()
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
/**
- TileMode.CLAMP 拉伸最后一个像素去铺满剩下的地方
- TileMode.MIRROR 通过镜像翻转铺满剩下的地方。
- TileMode.REPEAT 重复图片平铺整个画面(电脑设置壁纸)
- 在图片和显示区域大小不符的情况进行扩充渲染
/
/* - 位图渲染,BitmapShader(@NonNull Bitmap bitmap, @NonNull TileMode tileX, @NonNull TileMode tileY)
- Bitmap:构造shader使用的bitmap
- tileX:X轴方向的TileMode
- tileY:Y轴方向的TileMode
*/
val bitMapShader = BitmapShader(
mBitMap!!, Shader.TileMode.MIRROR,
Shader.TileMode.MIRROR
)
//设置图片效果
mPaint!!.setShader(bitMapShader)
//抗锯齿
mPaint!!.setAntiAlias(true)
//绘制圆
canvas.drawCircle(width/2f,height/2f,mHeight.toFloat(),mPaint!!)
}
}
参数的意思我注释很详细,我就不在过多说明了。
3. 线性渲染 LinearGradient

/**线性渲染
- x0, y0, 起始点
- x1, y1, 结束点
- int[] mColors, 中间依次要出现的几个颜色
- float[] positions 位置数组,position的取值范围[0,1],作用是指定几个颜色分别放置在那个位置上,
- 如果传null,渐变就线性变化。
- tile 用于指定控件区域大于指定的渐变区域时,空白区域的颜色填充方法
*/
var linearGradient = LinearGradient(
0f, 0f, 800f, 800f,
mColors, null, Shader.TileMode.CLAMP
)
// var linearGradient = LinearGradient(0f, 0f, 400f, 400f, mColors, null, Shader.TileMode.REPEAT)
mPaint!!.setShader(linearGradient)
canvas.drawRect(0f, 0f, 800f, 800f, mPaint!!)
4. 环形渲染 RadialGradient

/**
*
- 环形渲染
- centerX ,centerY:shader的中心坐标,开始渐变的坐标
- radius:渐变的半径
- centerColor,edgeColor:中心点渐变颜色,边界的渐变颜色
- colors:渐变颜色数组
- stops:渐变位置数组,类似扫描渐变的positions数组,取值[0,1],中心点为0,半径到达位置为1.0f
- tileMode:shader未覆盖以外的填充模式
*/
val mRadialGradient = RadialGradient(
width/2f,height/2f,width/3.toFloat(),
mColors, null, Shader.TileMode.REPEAT
)
mPaint!!.setShader(mRadialGradient)
canvas.drawCircle(width/2f,height/2f,width/3.toFloat(), mPaint!!)
复制代码
5. 扫描渲染 SweepGradient

/**
- 扫描渲染
- cx,cy 渐变中心坐标
- color0,color1:渐变开始结束颜色
- colors,positions:类似LinearGradient,用于多颜色渐变,positions为null时,根据颜色线性渐变
*/
val mSweepGradient = SweepGradient(width/2f,height/2f, mColors, null)
mPaint!!.setShader(mSweepGradient)
canvas.drawCircle(width/2f,height/2f,width/3.toFloat(), mPaint!!)
复制代码
6. 组合渲染 ComposeShader

/**
- 组合渲染,
- ComposeShader(@NonNull Shader shaderA, @NonNull Shader shaderB, Xfermode mode)
- ComposeShader(@NonNull Shader shaderA, @NonNull Shader shaderB, PorterDuff.Mode mode)
- shaderA,shaderB:要混合的两种shader
- Xfermode mode: 组合两种shader颜色的模式
- PorterDuff.Mode mode: 组合两种shader颜色的模式
*/
val bitMapShader = BitmapShader(
mBitMap!!, Shader.TileMode.REPEAT,
Shader.TileMode.REPEAT
)
val linearGradient = LinearGradient(
0f, 0f, 800f, 800f,
mColors, null, Shader.TileMode.CLAMP
)
val mComposeShader = ComposeShader(linearGradient, bitMapShader, PorterDuff.Mode.SRC_OVER)
mPaint!!.setShader(mComposeShader)
canvas.drawRect(0f, 0f, 800f, 1000f, mPaint!!)
7. 绘制心型 ComposeShader

//创建BitmapShader,用以绘制心
val mBitmap = (resources.getDrawable(R.mipmap.heart) as BitmapDrawable).bitmap
val bitmapShader = BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
//创建LinearGradien
《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享
t,用以产生从左上角到右下角的颜色渐变效果
val linearGradient = LinearGradient(
0f, 0f, mWidth.toFloat(), mHeight.toFloat(),
Color.BLUE, Color.RED, Shader.TileMode.CLAMP
)
//bitmapShader对应目标像素,linearGradient对应源像素,像素颜色混合采用MULTIPLY模式
val composeShader = ComposeShader(linearGradient, bitmapShader, PorterDuff.Mode.MULTIPLY)
// ComposeShader composeShader2 = new ComposeShader(composeShader, linearGradient, PorterDuff.Mode.MULTIPLY);
//将组合的composeShader作为画笔paint绘图所使用的shader
mPaint!!.setShader(composeShader)
//用composeShader绘制矩形区域
canvas.drawRect(0f, 0f, mBitmap.width.toFloat(), mBitmap.height.toFloat(), mPaint!!)
//所谓渲染就是对于我们绘制区域进行按照上诉渲染规则进行色彩的填充
9. 线性渲染-字体渐变 LinearGradient

class LinearGradientTextView : TextView {
/**
- 定义线性渐变
*/
private var mLinearGradient: LinearGradient? = null
/**
- 定义一个矩阵
*/
private var mGradientatrix: Matrix? = null
/**
- 定义一个画笔
*/
private var mPaint: Paint? = null
private var mViewWidth = 0
private var mTranslate = 0
private var delta = 15
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
/**
- 当字改变的时候回调
/
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
if (mViewWidth ==0){
//拿到当前 text 宽度
mViewWidth = measuredWidth
if (mViewWidth > 0){
//拿到当前画笔
mPaint = paint
//拿到 text
var text = text.toString()
//mViewWidth除字体总数就得到了每个字的像素 然后3 表示3个文字的像素
var size = 0;
//如果当前 text 长度大于 0
if (text.length > 0){
//拿到当前 3 个文字的像素
size = mViewWidth / text.length * 3
}else{//说明没有文字
size = mViewWidth
}
/**线性渲染
- x0, y0, 起始点
- x1, y1, 结束点
- int[] mColors, 中间依次要出现的几个颜色
- float[] positions 位置数组,position的取值范围[0,1],作用是指定几个颜色分别放置在那个位置上,
- 如果传null,渐变就线性变化。
- tile 用于指定控件区域大于指定的渐变区域时,空白区域的颜色填充方法
*/
//从左边 size 开始,左边看不见的地方开始,以滚动扫描的形式过来
mLinearGradient = LinearGradient(-size.toFloat(),0f,0f,0f, intArrayOf(0x33ffffff, -0x1, 0x33ffffff),
floatArrayOf(0f, 0.2f, 1f), Shader.TileMode.CLAMP)
//将线性渐变添加到 paint 中
mPaint!!.setShader(mLinearGradient)
//定义一个矩阵
mGradientatrix = Matrix()
}
}
}
/**
- 开始绘制
/
override fun draw(canvas: Canvas?) {
super.draw(canvas)
val measureWindth = paint.measureText(text.toString())
mTranslate += delta
/* - 如果位置已经移动到了边界,那么文字就开始往回滚动
- 但是如果小于 1 那么又开始递增,执行另一个逻辑
*/
if (mTranslate > measureWindth + 1 || mTranslate < 1){
delta = -delta
}
//将矩阵平移
mGradientatrix!!.setTranslate(mTranslate.toFloat(),0f)
mLinearGradient!!.setLocalMatrix(mGradientatrix)
//paint是textview的所以只需要不断色控制画笔的shader 然后利用矩阵控制位移即可
postInvalidateDelayed(30)
}
}
10. 雷达扫描 SweepGradient

/**
author : devyk on 2019-11-30 18:50blog : https://juejin.im/user/578259398ac2470061f3a3fb/postsgithub : https://github.com/yangkun19921001mailbox : yang1001yk@gmail.comdesc : This is RadarGradientView 渐变渲染/梯度渲染
*/
class RadarGradientView : View {
private var mWidth: Int = 0
private var mHeight: Int = 0
private val TAG = javaClass.simpleName
//五个圆
private val pots = floatArrayOf(0.05f, 0.1f, 0.15f, 0.2f, 0.25f, 0.3f, 0.35f)
private var scanShader: Shader? = null // 扫描渲染shader
private val scanSpeed = 10 // 扫描速度
private var scanAngle: Int = 0 // 扫描旋转的角度
private lateinit var mMatrix: Matrix // 旋转需要的矩阵
private var mPaintCircle = Paint() // 画圆用到的paint
private var mPaintRadar = Paint() // 扫描用到的paint
private val run = object : Runnable {
override fun run() {
scanAngle = (scanAngle + scanSpeed) % 125 //
Log.d(TAG,“scanAngle:$scanAngle”)
mMatrix.postRotate(scanSpeed.toFloat(), (mWidth / 2).toFloat(), (mHeight / 2).toFloat()) // 旋转矩阵
invalidate() // 通知view重绘
postDelayed(this, 50) // 调用自身 重复绘制
}
}
constructor(context: Context) : super(context) {
init()
}
private fun init() {
mMatrix = Matrix()
// 画圆用到的paint
mPaintCircle = Paint()
mPaintCircle.style = Paint.Style.STROKE // 描边
mPaintCircle.strokeWidth = 1f // 宽度
mPaintCircle.alpha = 100 // 透明度
mPaintCircle.isAntiAlias = true // 抗锯齿
mPaintCircle.color = Color.parseColor("#B0C4DE") // 设置颜色 亮钢兰色
// 扫描用到的paint
mPaintRadar = Paint()
mPaintRadar.style = Paint.Style.FILL_AND_STROKE // 填充
mPaintRadar.isAntiAlias = true // 抗锯齿
post(run)
}
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
init()
}
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
Log.d(TAG,“onDraw()”)
for (i in pots.indices) {
canvas.drawCircle((mWidth / 2).toFloat(), (mHeight / 2).toFloat(), mWidth * pots[i], mPaintCircle)
}
// 画布的旋转变换 需要调用save() 和 restore()
canvas.save()
scanShader = SweepGradient(
(mWidth / 2).toFloat(), (mHeight / 2).toFloat(),
intArrayOf(Color.TRANSPARENT, Color.parseColor("#84B5CA")), null
)
mPaintRadar.shader = scanShader // 设置着色器
canvas.concat(mMatrix)
canvas.drawCircle((mWidth / 2).toFloat(), (mHeight / 2).toFloat(), mWidth * pots[6], mPaintRadar)
canvas.restore()
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
Log.d(TAG,“onMeasure()”)
// 取屏幕的宽高是为了把雷达放在屏幕的中间
mWidth = measuredWidth
mHeight = measuredHeight
mHeight = Math.min(mWidth, mHeight)
mWidth = mHeight
}
}
11. 放大镜 BitmapShader

class ZoomImageView : View {
// 原图
private val mBitmap: Bitmap
// 放大后的图
private var mBitmapScale: Bitmap? = null
// 制作的圆形的图片(放大的局部),盖在Canvas上面
private val mShapeDrawable: ShapeDrawable
private val mMatrix: Matrix
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
init {
mBitmap = BitmapFactory.decodeResource(resources, R.mipmap.gild_3)
mBitmapScale = mBitmap
//放大后的整个图片
mBitmapScale = Bitmap.createScaledBitmap(
mBitmapScale!!, mBitmapScale!!.width * FACTOR,
mBitmapScale!!.height * FACTOR, true
)
val bitmapShader = BitmapShader(
mBitmapScale!!, Shader.TileMode.CLAMP,
Shader.TileMode.CLAMP
)
mShapeDrawable = ShapeDrawable(OvalShape())
mShapeDrawable.paint.shader = bitmapShader
// 切出矩形区域,用来画圆(内切圆)
mShapeDrawable.setBounds(0, 0, RADIUS * 2, RADIUS * 2)
mMatrix = Matrix()
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
// 1、画原图
canvas.drawBitmap(mBitmap, 0f, 0f, null)
// 2、画放大镜的图
mShapeDrawable.draw(canvas)
}
override fun onTouchEvent(event: MotionEvent): Boolean {
val x = event.x.toInt()
val y = event.y.toInt() - RADIUS
Log.d(“onTouchEvent”, “x:” + x + “y:” + y)
// 将放大的图片往相反的方向挪动
mMatrix.setTranslate((RADIUS - x * FACTOR).toFloat(), (RADIUS - y * FACTOR).toFloat())
mShapeDrawable.paint.shader.setLocalMatrix(mMatrix)
// 切出手势区域点位置的圆
mShapeDrawable.setBounds(x - RADIUS, y - RADIUS, x + RADIUS, y + RADIUS)
// invalidate()
postInvalidate()
return true
}
companion object {
//放大倍数
private val FACTOR = 3
//放大镜的半径
private val RADIUS = 300
}
}
滤镜

//平移运算—加法
ColorMatrix colorMartrix = new ColorMatrix(new float[]{
1, 0,0,0,0,
0,1,0,0,100,
0,0,1,0,0,
0,0,0,1,0,
});
//反相效果 – 底片效果
ColorMatrix colorMartrix = new ColorMatrix(new float[]{
-1, 0,0,0,255,
0,-1,0,0,255,
0,0,-1,0,255,
0,0,0,1,0,
});
//缩放运算—乘法 – 颜色增强
ColorMatrix colorMartrix = new ColorMatrix(new float[]{
1.2f, 0,0,0,0,
0,1.2f,0,0,0,
0,0,1.2f,0,0,
0,0,0,1.2f,0,
});
/** 黑白照片
- 是将我们的三通道变为单通道的灰度模式
- 去色原理:只要把R G B 三通道的色彩信息设置成一样,那么图像就会变成灰色,
- 同时为了保证图像亮度不变,同一个通道里的R+G+B =1
*/
ColorMatrix colorMartrix = new ColorMatrix(new float[]{
0.213f, 0.715f,0.072f,0,0,
0.213f, 0.715f,0.072f,0,0,
0.213f, 0.715f,0.072f,0,0,
0,0,0,1,0,
});
//发色效果—(比如红色和绿色交换)
ColorMatrix colorMartrix = new ColorMatrix(new float[]{
1,0,0,0,0,
0, 0,1,0,0,
0,1,0,0,0,
0,0,0,0.5F,0,
});
//复古效果
ColorMatrix colorMartrix = new ColorMatrix(new float[]{
1/2f,1/2f,1/2f,0,0,
1/3f, 1/3f,1/3f,0,0,
1/4f,1/4f,1/4f,0,0,
0,0,0,1,0,
});
复制代码
class FilterView : View {
private var paint = Paint()
lateinit var bitmap: Bitmap
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
/**
- 显示的高
*/
var showHeight = 0
init {
init()
}
private fun init() {
paint = Paint(Paint.ANTI_ALIAS_FLAG)
paint.color = Color.RED
bitmap = BitmapFactory.decodeResource(resources, R.mipmap.gild_3)
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
// //关闭单个View的硬件加速功
// // setLayerType(View.LAYER_TYPE_SOFTWARE,null);
//1. 缩放运算—乘法 – 颜色增强
val colorMartrix = ColorMatrix(
floatArrayOf(
1.2f, 0f, 0f, 0f, 0f,
0f, 1.2f, 0f, 0f, 0f,
0f, 0f, 1.2f, 0f, 0f,
0f, 0f, 0f, 1.2f, 0f
)
)
val rectF = RectF(
0f,
showHeight.toFloat() ,
(bitmap.width / 2).toFloat(),
(bitmap.height / 4).toFloat()
)
drawFilterBitmap(colorMartrix, canvas,rectF)
showHeight += bitmap.height / 4
//2 平移运算—加法
var colorMartrix2 = ColorMatrix(floatArrayOf(
1f, 0f,0f,0f,0f,
0f,1f,0f,0f,100f,
0f,0f,1f,0f,0f,
0f,0f,0f,1f,0f
))
val rectF2 = RectF(
0f,
showHeight.toFloat(),
(bitmap.width / 2).toFloat(),
(bitmap.height /4) * 2.toFloat()
)
drawFilterBitmap(colorMartrix2, canvas,rectF2)
showHeight += bitmap.height / 4
//3. 反相效果 – 底片效果
var colorMartrix3 = ColorMatrix(floatArrayOf(
-1f, 0f,0f,0f,255f,
0f,-1f,0f,0f,255f,
0f,0f,-1f,0f,255f,
0f,0f,0f,1f,0f
));
val rectF3 = RectF(
0f,
showHeight.toFloat(),
(bitmap.width / 2).toFloat(),
(bitmap.height /4) * 3.toFloat()
)
drawFilterBitmap(colorMartrix3, canvas,rectF3)
/**
- 4.黑白照片
- 是将我们的三通道变为单通道的灰度模式
- 去色原理:只要把R G B 三通道的色彩信息设置成一样,那么图像就会变成灰色,
- 同时为了保证图像亮度不变,同一个通道里的R+G+B =1
*/
var colorMartrix4 = ColorMatrix(floatArrayOf(
0.213f, 0.715f,0.072f,0f,0f,
0.213f, 0.715f,0.072f,0f,0f,
0.213f, 0.715f,0.072f,0f,0f,
0f,0f,0f,1f,0f
));
showHeight += bitmap.height / 4
val rectF4 = RectF(
bitmap.width/2f,
bitmap.height /2f,
(bitmap.width).toFloat(),
(bitmap.height /4) * 3.toFloat()
)
drawFilterBitmap(colorMartrix4, canvas,rectF4)
//5.发色效果—(比如红色和绿色交换)
var colorMartrix5 = ColorMatrix(floatArrayOf(
1f,0f,0f,0f,0f,
0f, 0f,1f,0f,0f,
0f,1f,0f,0f,0f,
0f,0f,0f,0.5F,0f
));
val rectF5 = RectF(
bitmap.width / 2f,
0f,
(bitmap.width / 2 * 2).toFloat(),
(bitmap.height /4) .toFloat()
)
drawFilterBitmap(colorMartrix5, canvas,rectF5)
//6.复古效果
var colorMartrix6= ColorMatrix(floatArrayOf(
1/2f,1/2f,1/2f,0f,0f,
1/3f, 1/3f,1/3f,0f,0f,
1/4f,1/4f,1/4f,0f,0f,
0f,0f,0f,1f,0f
));
val rectF6 = RectF(
bitmap.width / 2f,
bitmap.height /4f,
(bitmap.width / 2 * 2).toFloat(),
(bitmap.height /4 * 2) .toFloat()
)
drawFilterBitmap(colorMartrix6, canvas,rectF6)
}
private fun drawFilterBitmap(colorMartrix: ColorMatrix, canvas: Canvas,rectF: RectF) {
paint.colorFilter = ColorMatrixColorFilter(colorMartrix)
canvas.drawBitmap(bitmap, null, rectF, paint)
}
}
xfermode
private static final Xfermode[] sModes = {
new PorterDuffXfermode(PorterDuff.Mode.CLEAR), // 清空所有,要闭硬件加速,否则无效
new PorterDuffXfermode(PorterDuff.Mode.SRC), // 显示前都图像,不显示后者
new PorterDuffXfermode(PorterDuff.Mode.DST), // 显示后者图像,不显示前者
new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER), // 后者叠于前者
new PorterDuffXfermode(PorterDuff.Mode.DST_OVER), // 前者叠于后者
new PorterDuffXfermode(PorterDuff.Mode.SRC_IN), // 显示相交的区域,但图像为后者
new PorterDuffXfermode(PorterDuff.Mode.DST_IN), // 显示相交的区域,但图像为前者
new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT), // 显示后者不重叠的图像
new PorterDuffXfermode(PorterDuff.Mode.DST_OUT), // 显示前者不重叠的图像
new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP), // 显示前者图像,与后者重合的图像
new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP), // 显示后者图像,与前者重合的图像
new PorterDuffXfermode(PorterDuff.Mode.XOR), // 显示持有不重合的图像
new PorterDuffXfermode(PorterDuff.Mode.DARKEN), // 后者叠于前者上,后者与前者重叠的部份透明。要闭硬件加速,否则无效
new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN), // 前者叠于前者,前者与后者重叠部份透明。要闭硬件加速,否则无效
new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY), // 显示重合的图像,且颜色会合拼
new PorterDuffXfermode(PorterDuff.Mode.SCREEN) // 显示持有图像,重合的会变白
};

class XfermodeView : View {
lateinit var mPaint: Paint
internal var mItemSize = 0f
internal var mItemHorizontalOffset = 0f
internal var mItemVerticalOffset = 0f
internal var mCircleRadius = 0f
internal var mRectSize = 0f
internal var mCircleColor = -0x33bc//黄色
internal var mRectColor = -0x995501//蓝色
internal var mTextSize = 25f
constructor(context: Context) : super(context) {
init(null, 0)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
init(attrs, 0)
}
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
init(attrs, defStyle)
}
private fun init(attrs: AttributeSet?, defStyle: Int) {
if (Build.VERSION.SDK_INT >= 11) {
setLayerType(View.LAYER_TYPE_SOFTWARE, null)
}
mPaint = Paint(Paint.ANTI_ALIAS_FLAG)
mPaint.textSize = mTextSize
mPaint.textAlign = Paint.Align.CENTER
mItemHorizontalOffset = 0f
internal var mItemVerticalOffset = 0f
internal var mCircleRadius = 0f
internal var mRectSize = 0f
internal var mCircleColor = -0x33bc//黄色
internal var mRectColor = -0x995501//蓝色
internal var mTextSize = 25f
constructor(context: Context) : super(context) {
init(null, 0)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
init(attrs, 0)
}
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
init(attrs, defStyle)
}
private fun init(attrs: AttributeSet?, defStyle: Int) {
if (Build.VERSION.SDK_INT >= 11) {
setLayerType(View.LAYER_TYPE_SOFTWARE, null)
}
mPaint = Paint(Paint.ANTI_ALIAS_FLAG)
mPaint.textSize = mTextSize
mPaint.textAlign = Paint.Align.CENTER