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

/**

  • 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

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

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

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

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

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

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

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

尾声

如果你想成为一个优秀的 Android 开发人员,请集中精力,对基础和重要的事情做深度研究。

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

这里,笔者分享一份从架构哲学的层面来剖析的视频及资料给大家梳理了多年的架构经验,筹备近6个月最新录制的,相信这份视频能给你带来不一样的启发、收获。

Android进阶学习资料库

一共十个专题,包括了Android进阶所有学习资料,Android进阶视频,Flutter,java基础,kotlin,NDK模块,计算机网络,数据结构与算法,微信小程序,面试题解析,framework源码!

大厂面试真题

PS:之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

《2019-2021字节跳动Android面试历年真题解析》

本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

[外链图片转存中…(img-zo5RasVJ-1712231189692)]

本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值