背景
原生的TextView是支持跑马灯效果的,但是在项目中实际用了之后,达不到需求,原因是内容滚动太慢,速度无法调节。因此,需要自定义一个可以调节速度的跑马灯。
思路
目前实现的思路是对文本内容不断地重绘,同时改变每次重绘的坐标,来在视觉上达到内容在滚动的效果。缺点是如果每次改变的坐标差值太大,会有明显的卡顿效果。经过调试,下面源码中的速度感觉还可以接受,如果有特殊需求,自行在调试一下。
源码(Kotlin)
class CustomMarqueeView : AppCompatTextView {
enum class SpeedMode(val speed: Int) {
SLOW(3), NORM(6), FAST(9)
}
private var mViewWidth = 0
private var mViewHeight = 0
private var mScrollX = 0F
private var mSpeedMode = SpeedMode.NORM
private var mTextContentWidth = 0F
private var mTextContentHeight = 0F
private var mDrawTextY = 0F
constructor(context: Context) : this(context, null)
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
override fun onDraw(canvas: Canvas) {
if (text.isNullOrEmpty()) {
return
}
val x = mViewWidth - mScrollX
canvas.drawText(text, 0, text.length, x, mDrawTextY, paint)
mScrollX += mSpeedMode.speed
if (mScrollX >= (mViewWidth + mTextContentWidth)) {
mScrollX = 0F
}
invalidate()
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
mViewWidth = MeasureSpec.getSize(widthMeasureSpec)
mViewHeight = MeasureSpec.getSize(heightMeasureSpec)
mDrawTextY = mViewHeight / 2F + (mTextContentHeight / 2F - paint.fontMetrics.descent)
}
override fun setText(text: CharSequence?, type: BufferType?) {
super.setText(text, type)
if (text.isNullOrEmpty()) {
return
}
val rect = Rect()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
paint.getTextBounds(text, 0, text.length, rect)
} else {
paint.getTextBounds(text.toString(), 0, text.length, rect)
}
this.mTextContentWidth = rect.width().toFloat()
this.mTextContentHeight = paint.fontMetrics.descent - paint.fontMetrics.ascent
}
override fun setTextColor(color: Int) {
super.setTextColor(color)
paint.color = color
}
fun setSpeedMode(speedMode: SpeedMode) {
this.mSpeedMode = speedMode
}
}
- 自定义属性
<declare-styleable name="CustomMarqueeView">
<attr name="customScrollSpeed">
<enum name="fast" value="9" />
<enum name="medium" value="6" />
<enum name="slow" value="3" />
</attr>
</declare-styleable>