目录
-
什么是自定义View?
-
为什么需要自定义View?
-
自定义View的核心步骤
-
实战:实现一个圆形进度条
-
注意事项与优化建议
-
总结
1. 什么是自定义View?
在Android开发中,当系统提供的原生控件无法满足特定UI需求时,开发者可以通过继承View
或其子类(如TextView
、ImageView
)来创建自定义组件,这种技术称为自定义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 处理自定义属性
-
在
res/values/attrs.xml
中定义属性:
<declare-styleable name="CustomView"> <attr name="progressColor" format="color" /> <attr name="progressWidth" format="dimension" /> </declare-styleable>
运行 HTML
-
在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. 注意事项与优化建议
-
性能优化:
-
避免在
onDraw()
中创建对象 -
使用
clipRect()
限制绘制区域 -
考虑使用
Canvas.saveLayer()
时的性能损耗
-
-
内存泄漏:
-
及时移除回调/监听器
-
避免在View中持有Activity引用
-
-
硬件加速:
-
检查
View.isHardwareAccelerated
-
某些Canvas操作不支持硬件加速(需关闭)
-
6. 总结
通过本文我们学习了:
-
自定义View的基本实现流程
-
Kotlin在自定义View中的高效应用
-
属性自定义与Canvas绘图技巧
-
性能优化的关键点
推荐继续学习: