Android文字渐变的实现
最近设计师提了一个特殊字体,是从上到下渐变的效果。
正常是这样:
intArrayOf(startColor, endColor), // 只需两个颜色
但是我发现颜色不太对,颜色底部的太浅,顶部太深。优化下应该是这样:
intArrayOf(startColor, startColor, endColor, endColor),
可以这样写:
kotlin
class GradientTextView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : AppCompatTextView(context, attrs, defStyleAttr) {
private var startColor = 0x00FFFF.toInt()
private var endColor = 0xFFFFFF.toInt()
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
if (changed) updateGradient()
}
private fun updateGradient() {
if (width == 0 || height == 0) return
paint.shader = LinearGradient(
0f, 0F,
0f, height.toFloat(),
intArrayOf(startColor, startColor, endColor, endColor),
null,
Shader.TileMode.CLAMP
)
invalidate()
}
}
下面是AI逐行解释
这段代码是 Android 自定义 View 中用于创建和更新线性渐变效果的代码。让我逐步解释:
1. onLayout 方法
kotlin
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
if (changed) updateGradient()
}
- 作用:当 View 的布局发生变化时被调用
- 参数 :
changed: 布局是否改变(尺寸或位置变化)left/top/right/bottom: View 相对于父容器的位置坐标
- 逻辑 :只有在布局真正改变时(
changed == true)才更新渐变,避免不必要的重绘
2. updateGradient 方法
kotlin
private fun updateGradient() {
if (width == 0 || height == 0) return // ①
paint.shader = LinearGradient( // ②
0f, 0f, // 起点坐标 (x1, y1)
0f, height.toFloat(), // 终点坐标 (x2, y2)
intArrayOf(startColor, startColor, endColor, endColor), // ③
null, // ④
Shader.TileMode.CLAMP // ⑤
)
invalidate() // ⑥
}
关键点解析
① 尺寸检查
- 避免在 View 还未测量完成时创建渐变(width/height 为 0)
② LinearGradient 线性渐变
- 从
(0, 0)到(0, height)创建垂直渐变(从上到下)
③ 颜色数组
kotlin
intArrayOf(startColor, startColor, endColor, endColor)
- 包含 4 个颜色值,但只有两种颜色
- 这样配置会创建特殊的渐变效果(可能是为了控制渐变的分布)
④ 位置数组为 null
- 不指定颜色的位置,系统会均匀分布颜色
- 如果是
[0f, 0.3f, 0.7f, 1f]则可以精确控制每个颜色的位置
⑤ TileMode.CLAMP
- 超出渐变范围的区域使用边缘颜色填充
⑥ invalidate()
- 触发 View 重绘,使新的渐变生效
渐变效果示意
┌─────────────┐
│ startColor │ ← 顶部
│ startColor │
│ │
│ 渐变过渡 │
│ │
│ endColor │
│ endColor │ ← 底部
└─────────────┘
可能的改进建议
如果想要简单的双色渐变,可以简化为:
kotlin
paint.shader = LinearGradient(
0f, 0f,
0f, height.toFloat(),
intArrayOf(startColor, endColor), // 只需两个颜色
null,
Shader.TileMode.CLAMP
)