在移动应用开发中,跑马灯效果(Marquee)是一种常见的用户界面交互,用于展示超出显示范围的内容。Android 自带的 TextView 提供了跑马灯效果,但有时功能有限,难以满足定制化需求。因此,我们可以通过继承 AppCompatTextView,实现一个高性能、可控速率的自定义跑马灯控件 CustomMarqueeView。
功能介绍
CustomMarqueeView 具有以下特点:
- 支持多种滚动速度(快、中、慢)。
- 自动适配内容宽度,支持循环滚动。
- 文本居中显示,如果内容未超出宽度,则无需滚动。
- 可通过 XML 属性设置滚动速度。
实现代码解析
下面是 CustomMarqueeView 的完整实现及其关键部分的解析。
1. 类定义与常量设置
定义了一个继承自 AppCompatTextView 的控件,并设置了三种滚动速度常量:
companion object {
const val SPEED_FAST = 9
const val SPEED_MEDIUM = 6
const val SPEED_SLOW = 3
}
开发者可以通过 setScrollSpeed 方法动态调整滚动速度。
2. 属性初始化
在构造函数中,通过自定义属性读取滚动速度:
private fun initAttrs(context: Context, attrs: AttributeSet?) {
val typeArray = context.obtainStyledAttributes(attrs, R.styleable.CustomMarqueeView)
mMarqueeMode = typeArray.getInt(R.styleable.CustomMarqueeView_customScrollSpeed, mMarqueeMode)
typeArray.recycle()
}
此方法允许通过 XML 设置控件的滚动速度。
XML 示例:
<com.example.CustomMarqueeView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="这是一个跑马灯控件示例"
app:customScrollSpeed="6" />
3. 绘制滚动效果
核心逻辑集中在 onDraw 方法。主要实现了以下功能:
- 内容宽度检测:通过
getTextContentWidth方法计算文本宽度。 - 文本滚动逻辑:如果内容宽度超过控件宽度,则循环滚动;否则,文本居中显示。
滚动逻辑如下:
override fun onDraw(canvas: Canvas) {
val textContent = text.toString().trim()
val textWidth = getTextContentWidth()
val charWidth = paint.measureText(" ") * 20 // 用于填充间隔
val y = mViewHeight / 2F + getTextContentHeight() / 2
if (textWidth > mViewWidth) {
var x = -mScrollX % (textWidth + charWidth)
while (x < mViewWidth) {
canvas.drawText(textContent, x, y, paint)
x += textWidth + charWidth
}
mScrollX += mMarqueeMode
invalidate()
} else {
val x = (mViewWidth - textWidth) / 2F
canvas.drawText(textContent, x, y, paint)
}
}
核心逻辑解读:
- 超出宽度滚动:利用
mScrollX控制文本的滚动位置,滚动完一轮后重置偏移。 - 未超出宽度居中:如果文本未超出控件宽度,则居中显示,无需滚动。
4. 动态测量与调整
onMeasure 方法确保控件的宽高正确计算,为滚动和文本绘制提供基础数据:
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
mViewWidth = MeasureSpec.getSize(widthMeasureSpec)
mViewHeight = MeasureSpec.getSize(heightMeasureSpec)
}
5. 辅助方法
以下两个方法用于获取文本的宽度和高度,保证绘制精确:
private fun getTextContentWidth(): Int {
paint.getTextBounds(text.toString().trim(), 0, text.length, rect)
return rect.width()
}
private fun getTextContentHeight(): Int {
paint.getTextBounds(text.toString().trim(), 0, text.length, rect)
return rect.height()
}
使用方法
- 布局文件中使用:
确保在 res/values/attrs.xml 中定义自定义属性:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CustomMarqueeView">
<attr name="customScrollSpeed">
<enum name="slow" value="3" />
<enum name="medium" value="6" />
<enum name="fast" value="9" />
</attr>
</declare-styleable>
</resources>
然后在布局文件中引用:
<com.example.CustomMarqueeView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="这是一个自定义跑马灯效果示例"
app:customScrollSpeed="9" />
- 动态设置滚动速度:
val marqueeView = findViewById<CustomMarqueeView>(R.id.marquee_view)
marqueeView.setScrollSpeed(CustomMarqueeView.SPEED_MEDIUM)
总结
CustomMarqueeView 是一个简单易用、功能强大的自定义控件,适用于 Android 应用中需要展示滚动文本的场景。通过灵活设置滚动速度和支持文本居中显示,它可以满足大多数跑马灯效果需求,提升用户体验。
如果你在实际使用中有更多需求,还可以扩展控件,比如:
- 支持多行文本滚动。
- 增加滚动方向(从右向左或从左向右)。
- 支持动态更新文本内容。