字母栏
效果分析:
- 绘制 26 个字母
- 处理手势事件
自定义属性
<declare-styleable name="LetterView">
//绘制的文字大小
<attr name="letterSize" format="dimension"/>
//绘制文字的默认颜色
<attr name="letterColor" format="reference|color" />
</declare-styleable>
初始化属性
private var mNormalPaint = TextPaint()
private var mSelectPaint = TextPaint()
private var mLetters = arrayOf("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z")
private var mCurPosition = -1
init {
val ta = context.obtainStyledAttributes(attributes, R.styleable.LetterView)
val letterSize = ta.getDimensionPixelSize(R.styleable.LetterView_letterSize, sp2Px(14,resources))
val letterColor = ta.getColor(R.styleable.LetterView_letterColor,Color.BLACK)
ta.recycle()
mNormalPaint.textSize = letterSize.toFloat()
mNormalPaint.color = letterColor
mSelectPaint.textSize = letterSize.toFloat()
mSelectPaint.color = Color.RED
}
测量
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
//宽度 = 左内边距 + 右内边距 + 文字的宽度
val width = paddingLeft + paddingRight + mNormalPaint.measureText(mLetters[0]).toInt()
val height = MeasureSpec.getSize(heightMeasureSpec)
setMeasuredDimension(width,height)
}
绘制
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
val x = (width - mNormalPaint.measureText(mLetters[0]))/2
//获取字母的高度
val letterHeight = (height - paddingTop - paddingBottom)/mLetters.size
for(i in mLetters.indices){
val deltaY = (mNormalPaint.fontMetricsInt.bottom - mNormalPaint.fontMetricsInt.top)/2-mNormalPaint.fontMetricsInt.bottom
val baseY = deltaY + letterHeight/2 + letterHeight * i
if(i == mCurPosition){
canvas.drawText(mLetters[i],x,baseY.toFloat(),mSelectPaint)
}else{
canvas.drawText(mLetters[i],x,baseY.toFloat(),mNormalPaint)
}
}
}
手势
override fun onTouchEvent(event: MotionEvent): Boolean {
when(event.action){
MotionEvent.ACTION_DOWN,MotionEvent.ACTION_MOVE->{
val y= event.y
val position = (y / ((height - paddingTop - paddingBottom) / mLetters.size)).toInt()
//如果当前 position 与之前 position 相同则不需要重新绘制
if(position == mCurPosition){
return false
}
mCurPosition = position
invalidate()
}
}
return true
}