Android-高级-UI-进阶之路(四)-Paint-渲染-滤镜-xfermode-使用

这篇具有很好参考价值的文章主要介绍了Android-高级-UI-进阶之路(四)-Paint-渲染-滤镜-xfermode-使用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Android-高级-UI-进阶之路(四)-Paint-渲染-滤镜-xfermode-使用,程序员,android,ui

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

Android-高级-UI-进阶之路(四)-Paint-渲染-滤镜-xfermode-使用,程序员,android,ui

/**线性渲染

  • 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

Android-高级-UI-进阶之路(四)-Paint-渲染-滤镜-xfermode-使用,程序员,android,ui

/**
*

  • 环形渲染
  • 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

Android-高级-UI-进阶之路(四)-Paint-渲染-滤镜-xfermode-使用,程序员,android,ui

/**

  • 扫描渲染
  • 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

Android-高级-UI-进阶之路(四)-Paint-渲染-滤镜-xfermode-使用,程序员,android,ui

/**

  • 组合渲染,
  • 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

Android-高级-UI-进阶之路(四)-Paint-渲染-滤镜-xfermode-使用,程序员,android,ui

//创建BitmapShader,用以绘制心
val mBitmap = (resources.getDrawable(R.mipmap.heart) as BitmapDrawable).bitmap
val bitmapShader = BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
//创建LinearGradient,用以产生从左上角到右下角的颜色渐变效果
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

Android-高级-UI-进阶之路(四)-Paint-渲染-滤镜-xfermode-使用,程序员,android,ui

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

Android-高级-UI-进阶之路(四)-Paint-渲染-滤镜-xfermode-使用,程序员,android,ui

/**

  • 
    
  • author  : devyk on 2019-11-30 18:50
    
  • blog    : https://juejin.im/user/578259398ac2470061f3a3fb/posts
    
  • github  : https://github.com/yangkun19921001
    
  • mailbox : yang1001yk@gmail.com
    
  • desc    : 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

Android-高级-UI-进阶之路(四)-Paint-渲染-滤镜-xfermode-使用,程序员,android,ui

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
}
}

滤镜

Android-高级-UI-进阶之路(四)-Paint-渲染-滤镜-xfermode-使用,程序员,android,ui

//平移运算—加法
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) // 显示持有图像,重合的会变白
};

Android-高级-UI-进阶之路(四)-Paint-渲染-滤镜-xfermode-使用,程序员,android,ui

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
mPaint.strokeWidth = 2f
}

override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
//设置背景色
// canvas.drawARGB(255, 139, 197, 186);

val canvasWidth = canvas.width
val canvasHeight = canvas.height

for (row in 0…3) {
for (column in 0…3) {
canvas.save()
val layer =
canvas.saveLayer(0f, 0f, canvasWidth.toFloat(), canvasHeight.toFloat(), null, Canvas.ALL_SAVE_FLAG)
mPaint.xfermode = null
val index = row * 4 + column
val translateX = (mItemSize + mItemHorizontalOffset) * column
val translateY = (mItemSize + mItemVerticalOffset) * row
canvas.translate(translateX, translateY)
//画文字
val text = sLabels[index]
mPaint.color = Color.BLACK
val textXOffset = mItemSize / 2
val textYOffset = mTextSize + (mItemVerticalOffset - mTextSize) / 2
canvas.drawText(text, textXOffset, textYOffset, mPaint)
canvas.translate(0f, mItemVerticalOffset)
//画边框
mPaint.style = Paint.Style.STROKE
mPaint.color = -0x1000000
canvas.drawRect(2f, 2f, mItemSize - 2, mItemSize - 2, mPaint)
mPaint.style = Paint.Style.FILL
//画圆
mPaint.color = mCircleColor
val left = mCircleRadius + 3
val top = mCircleRadius + 3
canvas.drawCircle(left, top, mCircleRadius, mPaint)
mPaint.xfermode = sModes[index]
//画矩形
mPaint.color = mRectColor
val rectRight = mCircleRadius + mRectSize
val rectBottom = mCircleRadius + mRectSize
canvas.drawRect(left, top, rectRight, rectBottom, mPaint)
mPaint.xfermode = null
//canvas.restore();
canvas.restoreToCount(layer)
}
}
}

override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
mItemSize = w / 4.5f
mItemHorizontalOffset = mItemSize / 6
mItemVerticalOffset = mItemSize * 0.426f
mCircleRadius = mItemSize / 3
mRectSize = mItemSize * 0.6f
}

companion object {

private val sModes = arrayOf(
PorterDuffXfermode(PorterDuff.Mode.CLEAR),
PorterDuffXfermode(PorterDuff.Mode.SRC),
PorterDuffXfermode(
PorterDuff.Mode.DST
),
PorterDuffXfermode(PorterDuff.Mode.SRC_OVER),
PorterDuffXfermode(PorterDuff.Mode.DST_OVER),
PorterDuffXfermode(
PorterDuff.Mode.SRC_IN
),
PorterDuffXfermode(PorterDuff.Mode.DST_IN),
PorterDuffXfermode(PorterDuff.Mode.SRC_OUT),
PorterDuffXfermode(
PorterDuff.Mode.DST_OUT
),
PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP),
PorterDuffXfermode(PorterDuff.Mode.DST_ATOP),
PorterDuffXfermode(
PorterDuff.Mode.XOR
),
PorterDuffXfermode(PorterDuff.Mode.DARKEN),
PorterDuffXfermode(PorterDuff.Mode.LIGHTEN),
PorterDuffXfermode(
PorterDuff.Mode.MULTIPLY
),
PorterDuffXfermode(PorterDuff.Mode.SCREEN)
)

private val sLabels = arrayOf(
“Clear”,
“Src”,
“Dst”,
“SrcOver”,
“DstOver”,
“SrcIn”,
“DstIn”,
“SrcOut”,
“DstOut”,
“SrcATop”,
“DstATop”,
“Xor”,
“Darken”,
“Lighten”,
“Multiply”,
“Screen”
)
}
}
复制代码

1. 画圆角 PorterDuff.Mode.DST_IN

public class RoudImageView : View {

constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {
init()
}
var mBitPaint = Paint()
private lateinit var mBmpDST: Bitmap
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

Android-高级-UI-进阶之路(四)-Paint-渲染-滤镜-xfermode-使用,程序员,android,ui

Android-高级-UI-进阶之路(四)-Paint-渲染-滤镜-xfermode-使用,程序员,android,ui

Android-高级-UI-进阶之路(四)-Paint-渲染-滤镜-xfermode-使用,程序员,android,ui

Android-高级-UI-进阶之路(四)-Paint-渲染-滤镜-xfermode-使用,程序员,android,ui

Android-高级-UI-进阶之路(四)-Paint-渲染-滤镜-xfermode-使用,程序员,android,ui

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

Android-高级-UI-进阶之路(四)-Paint-渲染-滤镜-xfermode-使用,程序员,android,ui
最后

对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。

同时我经过多年的收藏目前也算收集到了一套完整的学习资料以及高清详细的Android架构进阶学习导图及笔记分享给大家,希望对想成为架构师的朋友有一定的参考和帮助。

下面是部分资料截图,诚意满满:特别适合有开发经验的Android程序员们学习。

Android-高级-UI-进阶之路(四)-Paint-渲染-滤镜-xfermode-使用,程序员,android,ui

不论遇到什么困难,都不应该成为我们放弃的理由!

如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言,一定会认真查询,修正不足,谢谢。

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!文章来源地址https://www.toymoban.com/news/detail-853619.html

42739097)]

[外链图片转存中…(img-UuU2nsoz-1712542739097)]

[外链图片转存中…(img-wQLTEwV0-1712542739097)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

Android-高级-UI-进阶之路(四)-Paint-渲染-滤镜-xfermode-使用,程序员,android,ui
最后

对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。

同时我经过多年的收藏目前也算收集到了一套完整的学习资料以及高清详细的Android架构进阶学习导图及笔记分享给大家,希望对想成为架构师的朋友有一定的参考和帮助。

下面是部分资料截图,诚意满满:特别适合有开发经验的Android程序员们学习。

[外链图片转存中…(img-vmxPZ5SO-1712542739097)]

不论遇到什么困难,都不应该成为我们放弃的理由!

如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言,一定会认真查询,修正不足,谢谢。

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

到了这里,关于Android-高级-UI-进阶之路(四)-Paint-渲染-滤镜-xfermode-使用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android-高级-UI-进阶之路-(七)-SVG-基础使用-+-绘制中国地图,Android面试中常问的MMAP到底是啥东东

    iv.setImageDrawable(animatedVectorDrawable) val animatable = iv.drawable as Animatable animatable.start() } } 输入搜索动画 利用在线绘制 SVG 图标网站 制作搜索图标 可以自己随意捣鼓绘制,绘制好了之后点击视图-源代码,将 SVG 代码复制出来保存成 search_svg.xml 在线转换 svg2vector 点击空白或者直接将

    2024年04月25日
    浏览(33)
  • Android架构进阶之高级UI系列(精编解析,值得收藏)

    public FrameHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_DO_FRAME: // 执行doFrame // 如果启用VSYNC机制,当VSYNC信号到来时触发 doFrame(System.nanoTime(), 0); break; case MSG_DO_SCHEDULE_VSYNC: // 申请VSYNC信号,例如当前需要绘制任务时 doScheduleVsync()

    2024年04月14日
    浏览(43)
  • Android架构进阶之高级UI系列(精编解析,值得收藏),Android开发面试技能介绍

    CallbackRecord callbacks; synchronized (mLock) { final long now = System.nanoTime(); // 根据指定的类型CallbackkQueue中查找到达执行时间的CallbackRecord callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked( now / TimeUtils.NANOS_PER_MS); if (callbacks == null) { return; } mCallbacksRunning = true; if (callbackType == Choreograph

    2024年04月13日
    浏览(28)
  • Canvas中的裁剪师讲解与实战——Android高级UI(1),Android体系化进阶学习图谱

    从今天开始我们聊一聊 Canvas 的API,因为Canvas的API较多,所以我们分为几次分享,首先分享的是裁剪类型的API使用。话不多说,先上实战图。 老夫的少女心 源码地址文末会给出,了解原理才能更好地驾驭。 分享前,我们先来聊聊,在我们生活中如何绘制一张如下的图。 我们

    2024年04月13日
    浏览(60)
  • 2023年软件测试工程师,初级到高级进阶路线指南,测试之路...

    提到软件测试工程师时,很多人依然会联想到那些“点点点”并企图在“点点点”中找到缺陷的人,也就是大家常说的依照测试规范和测试案例来对软件进行测试,检查软件是不是有缺陷,判断软件是不是稳定。但这其实是一个很不好的观点。 近年来,随着各大互联网企业的

    2024年02月09日
    浏览(44)
  • Unity进阶之路(2)UI Toolkit

    UI Toolkit是Unity内置的一个游戏UI解决方案。借鉴了web前端的设计模式。 web前端使用css,html,js。 其中css定义样式 html定义层级 js处理逻辑 UI Toolkit则是使用uss,uxml,C# 如果直接使用Unity提供的可视化UI创建工具创建UI面板,一个一个添加元素,只会生成uxml文件,样式直接通过内

    2024年04月16日
    浏览(25)
  • Android Xfermode 使用解析

    自定义绘制之图片 canvar.drawBitmap() ,BitMapFactory 加载本地图片优化版 inJustDecodeBounds  读取上下左右以及大小 等 信息 drawBitmap(bitmap,left,top,paint) drawOval(left,top,right,bottom) 画椭圆 paint.setXfremode() // 现在只剩一种 PorterDuffXfermode val count = canvar.saveLayer(bounds,paint) 挖空的区域 返回oc

    2024年02月11日
    浏览(18)
  • Android进阶之路 - 字体自适应

    开发中有很多场景需要进行自适应适配,但是关于这种字体自适应,我也是为数不多的几次使用,同时也简单分析了下源码,希望我们都有收获 很多时候控件的宽度是有限的,而要实现比较好看的UI效果,常见的处理方式应该有以下几种 默认执行多行显示 单行显示,不足部

    2024年02月08日
    浏览(27)
  • Android进阶之路 - 背景阴影、阴影背景

    不知道你是不是也经常听到这些话:你这个没有阴影效果;你这个阴影太浓了;你这个阴影太粗了;你这个阴影太实了;你这个阴影颜色也不对,你这个阴影… 在正式开发中,临近上线前有个环节叫UI验收(产品验收在其前后均可),主要查看开发效果与设计图是否统一,当

    2024年02月04日
    浏览(27)
  • Android中Paint字体的灵活使用

    在Android开发中,Paint是一个非常重要的绘图工具,可以用于在控制台应用程序或Java GUI应用程序中绘制各种形状和图案。其中,Paint.setText()方法是用于设置Paint绘制的文本内容的。在Android开发中,如果你想要设置文本内容,那么你必须了解如何使用Paint绘制文本,否则你的应用

    2024年02月02日
    浏览(25)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包