第一章:Android自定义View概述
各位同学,欢迎来到《Android自定义View与Kotlin绘图从入门到精通》的第一课。
说实话,我刚开始学Android的时候,最怕的就是自定义View。总觉得那是大神才碰的东西。后来做项目做多了才发现——自定义View没那么玄乎,它其实就是你给Android系统画图、写交互的一套工具。
今天咱们先聊聊最基础的问题:什么是自定义View?为什么需要它?它有哪些分类?
1.1 什么是自定义View
先问个问题:你平时用的Button、TextView、ImageView,它们是什么?
它们都是View。Android系统帮我们写好了这些控件的绘制逻辑和交互逻辑。但有时候,系统提供的控件不够用——比如你想画一个圆形进度条、一个带波浪效果的图表、一个可以拖拽排序的卡片……这时候,你就得自己动手写一个View。
自定义View,说白了就是继承View或其子类,重写它的绘制、测量、触摸等方法,实现你想要的效果。
我个人的理解是:系统给你搭好了画架和画布,你只需要拿起画笔,画出你想要的东西。
核心要点:自定义View = 继承View + 重写关键方法 + 实现自定义逻辑
1.2 为什么需要自定义View
你可能会想:系统控件那么多,还不够用吗?
嗯,说实话,大部分场景确实够用。但遇到下面这些情况,你就不得不自己动手了:
- 系统控件无法满足UI设计稿——设计师给你一个带渐变、圆角、阴影的复杂按钮,系统Button搞不定
- 需要高性能绘制——比如实时刷新的图表、动画,用布局嵌套会卡成PPT
- 需要特殊交互——比如拖拽排序、手势缩放、多点触控
- 复用性高——一个自定义View封装好,整个项目到处用,省时省力
我记得有一次做电商项目,产品经理要求首页的秒杀倒计时做成圆形进度条,中间显示剩余时间。用系统控件?根本不可能。最后我写了一个自定义View,半小时搞定,还顺便封装成了通用组件,后来好几个页面都用了。
我的建议:不要为了炫技而自定义View。能用系统控件解决的,就用系统控件。只有系统控件确实搞不定时,才考虑自定义。
1.3 自定义View的分类
自定义View按实现方式,我一般分成三类。你想想看,其实就这三种路子:
| 分类 | 实现方式 | 适用场景 | 难度 |
|---|---|---|---|
| 组合控件 | 将多个系统控件组合成一个新的View | 比如自定义标题栏、搜索框、带图标的按钮 | ⭐ |
| 继承系统控件 | 继承Button、TextView等,扩展功能 | 比如带倒计时的Button、可滚动的TextView | ⭐⭐ |
| 完全自定义 | 继承View,重写onDraw、onMeasure等 | 比如图表、进度条、游戏画面 | ⭐⭐⭐ |
组合控件是最简单的。说白了就是把几个系统控件拼在一起,写成一个类。比如你经常看到的带图标的输入框,就是EditText和ImageView的组合。
继承系统控件稍微进阶一点。比如你想让Button支持倒计时,直接继承Button,加个计时器逻辑就行。我刚开始做自定义View时,就是从这条路入门的。
完全自定义是最难的,也是咱们这门课的重点。你需要自己控制绘制、测量、布局、触摸事件。但别怕,后面我会一步步带你走通。
1.4 实现方式概览
不管哪种分类,自定义View的核心步骤其实就这几步:
- 创建类——继承View或其子类
- 重写构造方法——至少重写一个带Context和AttributeSet的构造
- 重写onMeasure——告诉系统这个View要占多大地方
- 重写onDraw——在这里画你想要的内容
- 处理触摸事件——如果需要交互,重写onTouchEvent
给你看个最简单的例子——一个画红色圆圈的View:
class CircleView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
private val paint = Paint().apply {
color = Color.RED
style = Paint.Style.FILL
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
// 在View中心画一个半径为100px的红色圆
val cx = width / 2f
val cy = height / 2f
canvas.drawCircle(cx, cy, 100f, paint)
}
}
这段代码很简单,但包含了自定义View的核心骨架。你把它放到布局里,就能看到一个红色圆圈。
注意:onDraw方法会被频繁调用(比如界面刷新、动画),所以里面不要创建对象,不要做耗时操作。Paint、Path这些对象,最好在构造方法里初始化好。
我曾经犯过一个错误——在onDraw里new了一个Paint对象,结果界面稍微有点动画,内存就蹭蹭往上涨。后来用Profiler一查,发现onDraw每秒调了60次,每次都在创建对象……嗯,从那以后我再也不敢在onDraw里new东西了。
1.5 本章小结
今天咱们聊了自定义View的基本概念:
- 什么是自定义View——继承View,重写方法,实现自定义效果
- 为什么需要它——系统控件不够用、需要高性能、特殊交互、复用
- 三种分类——组合控件、继承系统控件、完全自定义
- 核心步骤——创建类、重写构造、onMeasure、onDraw、触摸事件
下一章,咱们会深入Kotlin的绘图基础——Canvas和Paint。你会真正拿起画笔,画出第一个属于自己的图形。
准备好了吗?咱们下章见。