为了账号安全,请及时绑定邮箱和手机立即绑定

Kotlin编写自定义控件复习笔记

标签:
Kotlin

最近一年在公司要么写React Native,要么写前端WEB,好久没有写安卓原生代码和Kotlin了,刚刚来了个需求,RN项目安卓端更新不用跳转应用市场,直接通过后台的url下载apk,下载apk的时候进度条是定制的,如图:

webp

更新UI图


ok,这就是一个很简单的弹框,其中进度条、进度文字、进度标识图片这些因素是和进度搭边的,所以把他们单独抽取出来做成一个控件CarProgressView,先上代码:

package com.carfinanceapp.updateimport android.content.Contextimport android.graphics.*import android.util.AttributeSetimport android.view.Viewimport com.carfinanceapp.Rimport com.carfinanceapp.utils.dp2pxclass CarProgressView @JvmOverloads constructor(        context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : View(context, attrs, defStyleAttr) {
    var progress = 0
        set(value) {
            field = value
            invalidate()
        }    private var numPaint = Paint(Paint.ANTI_ALIAS_FLAG)    private var bgPaint = Paint(Paint.ANTI_ALIAS_FLAG)    private var linePaint = Paint(Paint.ANTI_ALIAS_FLAG)    private var carPaint = Paint(Paint.ANTI_ALIAS_FLAG)    private var bgRect = RectF()    private var lineRect = RectF()    private val carBitmap = BitmapFactory.decodeResource(resources, R.drawable.ic_progress_car)

    init {
        numPaint.textAlign = Paint.Align.CENTER
        numPaint.textSize = 24f.dp2px()
        numPaint.color = Color.parseColor("#52D46E")
        bgPaint.color = Color.parseColor("#F0F0F0")
        linePaint.color = Color.parseColor("#52D46E")
        carPaint.isFilterBitmap = true
    }


    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        canvas ?: return
        canvas.drawText("$progress%", measuredWidth / 2f, 30f.dp2px(), numPaint)
        drawBg(canvas)
        drawProgress(canvas)
        drawCar(canvas)
    }    private fun drawBg(canvas: Canvas) {
        bgRect.top = 50f.dp2px()
        bgRect.left = measuredWidth * 0.06f
        bgRect.right = measuredWidth * 0.94f
        bgRect.bottom = 55f.dp2px()
        canvas.drawRoundRect(bgRect, 5f.dp2px(), 5f.dp2px(), bgPaint)
    }    private fun drawProgress(canvas: Canvas) {
        lineRect.top = 49.5f.dp2px()
        lineRect.left = measuredWidth * 0.06f
        lineRect.right = measuredWidth * 0.94f * progress / 100f
        lineRect.bottom = 55.5f.dp2px()
        canvas.drawRoundRect(lineRect, 5f.dp2px(), 5f.dp2px(), linePaint)
    }    private fun drawCar(canvas: Canvas) {        //start -5 end -35
        canvas.drawBitmap(carBitmap, measuredWidth * 0.94f * progress / 100f - 5.dp2px() - (0.3f * progress).dp2px(), 45f.dp2px(), carPaint)
    }
}
  1. 重载方法注解 @JvmOverloads
    首先看类文件的开头,正常来说Kotlin继承父类或者是实现接口都是通过:来的,例如下面这些

//无参继承open class Fatherclass Test() : Father()//有参继承open class Father2(age: Int)class Test2(age: Int) : Father2(age)class Test3() : Father2(99)class Test4(age: Int) : Father2(99)

上面这些都是单构造方法,没有重载的,像安卓自定义View,继承于View就有四个重载方法,从最少传入Context,到最多传入Context,AttributeSet,defStyleAttr,defStyleRes这四个,Kotlin重载构造方法只需要使用@JvmOverloads constructor就可以了,而方法fun前面只用加 @JvmOverloads就行了

  1. field成员变量自带get、set方法
    看本类第一个成员变量:

var progress = 0        set(value) {
            field = value
            invalidate()
        }

kotlin默认所有成员变量和方法都是public的,如果不想要public,得加上private,声明变量使用var或者val,一个可变一个类似于final不可变
所以第一行var progress = 0等价于java代码:int progress = 0且有两个public的方法,一个getProgress,一个getProgress
下面的 set(value) {...}就是重写了这个默认提供的set方法,加了一个刷新界面显示的invalidate()

  1. init初始化代码块
    kotlin把构造方法的参数声明在类名后面了,也没有构造方法的fun,所以类创建的时候需要初始化的代码就要写在init{...}里面

  2. 扩展方法
    这个就好玩了,比如我init代码中的第二行   :
    numPaint.textSize = 24f.dp2px()
    这里24f.dp2px()就是我给Float添加的扩展方法dp2px,扩展方法声明很简单,在任意kt文件里面都可以,去年一个项目中创建了一个NumberExtend.kt就直接拿来用了,里面就是各种dp和px互相转换的扩展方法,代码如下:

package com.carfinanceapp.utilsimport android.content.res.Resourcesimport android.view.ViewGroup/**
 * Created by liutanglei on 2017/11/4
 */fun Int.dp2px(): Int {    if (toInt() in intArrayOf(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)) {        return this
    }    return (this * (Resources.getSystem().displayMetrics.densityDpi / 160f)).toInt()
}

fun Int.px2dp(): Int {    if (toInt() in intArrayOf(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)) {        return this
    }
    val metrics = Resources.getSystem().displayMetrics    return this / (metrics.densityDpi / 160)
}

fun Float.dp2px(): Float {    if (toInt() in intArrayOf(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)) {        return this
    }    return this * (Resources.getSystem().displayMetrics.densityDpi / 160f)
}

如上面所示,格式就是fun 类名.扩展方法名():返回值{扩展代码}
同理还有扩展属性,这里我没用使用,效果的话就是扩展一个没有属性,和这个类似

至于进度条控件的话,用画布画灰色的背景,绿色的进度,绿色的文字,还有汽车的图片,除了第一个,其他三个都要随着当前的progress改变,这些没什么好说的

对了,kotlin拼接字符串也很方便,"${变量}字符串" , 和es6里面的`${变量}字符串`有异曲同工之妙

写到这里马上就要下班了,总结一下就是kotlin能减少大量冗余的java代码,更优雅更快速的开发工程,有机会用就尽量用吧,不说了,准备下班溜了



作者:逆水行舟丶
链接:https://www.jianshu.com/p/627c42bbdd61


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消