Android开发实战:用Kotlin手把手教你自定义View


目录

  1. 什么是自定义View?

  2. 为什么需要自定义View?

  3. 自定义View的核心步骤

  4. 实战:实现一个圆形进度条

  5. 注意事项与优化建议

  6. 总结


1. 什么是自定义View?

在Android开发中,当系统提供的原生控件无法满足特定UI需求时,开发者可以通过继承View或其子类(如TextViewImageView)来创建自定义组件,这种技术称为自定义View

2. 为什么需要自定义View?

  • 实现独特的UI设计效果

  • 优化复杂布局的性能

  • 封装可复用的UI组件

  • 处理特殊的交互逻辑

3. 自定义View的核心步骤

3.1 继承View类

class CustomView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr)

3.2 重写关键方法

方法作用
onMeasure()测量View的宽高
onDraw()执行绘制操作
onLayout()确定子View位置(仅ViewGroup需要)

示例:测量View大小

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
    val minWidth = 200 // 最小宽度
    val minHeight = 200 // 最小高度
    setMeasuredDimension(
        resolveSize(minWidth, widthMeasureSpec),
        resolveSize(minHeight, heightMeasureSpec)
    )
}

3.3 处理自定义属性

  1. res/values/attrs.xml中定义属性:

<declare-styleable name="CustomView">
    <attr name="progressColor" format="color" />
    <attr name="progressWidth" format="dimension" />
</declare-styleable>

运行 HTML

  1. 在View中读取属性:

init {
    context.theme.obtainStyledAttributes(
        attrs,
        R.styleable.CustomView,
        0, 0
    ).apply {
        try {
            progressColor = getColor(R.styleable.CustomView_progressColor, Color.RED)
            progressWidth = getDimension(R.styleable.CustomView_progressWidth, 10f)
        } finally {
            recycle()
        }
    }
}

4. 实战:实现一个圆形进度条

4.1 完整代码实现

class CircleProgressView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

    private var progress = 0f
    private var progressColor = Color.RED
    private var progressWidth = 20f
    private val paint = Paint(Paint.ANTI_ALIAS_FLAG)

    init {
        // 初始化属性读取
        // ...(参考3.3节代码)
        paint.style = Paint.Style.STROKE
        paint.strokeWidth = progressWidth
        paint.color = progressColor
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        val centerX = width / 2f
        val centerY = height / 2f
        val radius = (width.coerceAtMost(height) - progressWidth) / 2f
        
        // 绘制背景圆
        paint.alpha = 50
        canvas.drawCircle(centerX, centerY, radius, paint)
        
        // 绘制进度
        paint.alpha = 255
        val sweepAngle = 360 * progress
        canvas.drawArc(
            centerX - radius, centerY - radius,
            centerX + radius, centerY + radius,
            -90f, sweepAngle, false, paint
        )
    }

    fun setProgress(progress: Float) {
        this.progress = progress.coerceIn(0f, 1f)
        invalidate() // 触发重绘
    }
}

4.2 XML中使用

<com.example.app.CircleProgressView
    android:layout_width="200dp"
    android:layout_height="200dp"
    app:progressColor="#FF5722"
    app:progressWidth="8dp"/>

5. 注意事项与优化建议

  1. 性能优化

    • 避免在onDraw()中创建对象

    • 使用clipRect()限制绘制区域

    • 考虑使用Canvas.saveLayer()时的性能损耗

  2. 内存泄漏

    • 及时移除回调/监听器

    • 避免在View中持有Activity引用

  3. 硬件加速

    • 检查View.isHardwareAccelerated

    • 某些Canvas操作不支持硬件加速(需关闭)

6. 总结

通过本文我们学习了:

  • 自定义View的基本实现流程

  • Kotlin在自定义View中的高效应用

  • 属性自定义与Canvas绘图技巧

  • 性能优化的关键点

推荐继续学习

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值