前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >2022-11-10-写控件

2022-11-10-写控件

作者头像
三流编程
发布2022-11-13 09:11:22
2080
发布2022-11-13 09:11:22
举报

开会,工作,未学习。


自定义控件 SideBar,自定义了几个属性,即文字大小 textSize,文字颜色和选中后的颜色,还有文件间的垂直边距 textVerticalMargin。

代码语言:javascript
复制
class SideBar @JvmOverloads constructor(  
    context: Context,  
    attrs: AttributeSet? = null,  
    defStyleAttr: Int = 0,  
    defStyleRes: Int = 0  
) : View(context, attrs, defStyleAttr, defStyleRes) {  
    
    private val paint: Paint = Paint().apply { textAlign = Paint.Align.CENTER } 

    var textSize = 0f
    var textColor = 0  
    var textColorSelected = 0  
    var textVerticalMargin = 0f  
        
    init {  
        val attributes = context.obtainStyledAttributes(attrs, R.styleable.SideBar)  
  
        textSize = attributes.getDimension(R.styleable.SideBar_textSize, 20f)  
        textColor = attributes.getColor(R.styleable.SideBar_textColor, Color.parseColor("#1B6EFD"))  
        textColorSelected = attributes.getColor(R.styleable.SideBar_textColorSelected, Color.parseColor("#1B6EFD"))  
        textVerticalMargin = attributes.getDimension(R.styleable.SideBar_textVerticalMargin, 4f)  
  
        attributes.recycle()  
    }  
}

当然绘制文字,需要知道高度。paint 设置水平居中,垂直位置文字以 baseline 为坐标,所以选出文字的高度 textHeight,减去它下面的 descent,就是文字 baseline 的位置。

代码语言:javascript
复制
private var textHeight = 0f  
private var fontDescent = 0f 

private fun getFontMetrics(textSize: Float) : Paint.FontMetrics {  
    paint.textSize = textSize  
    val fontMetrics = Paint.FontMetrics()  
    paint.getFontMetrics(fontMetrics)  
    return fontMetrics  
}  

var textSize = 0f  
    set(value) {  
        field = value  
        paint.textSize = value  
        val metrics = getFontMetrics(value)  
        textHeight = abs(metrics.descent - metrics.ascent)  
        fontDescent = abs(metrics.descent)  
    }  

在设置 textSize 大小后,立即重新计算文字的高度 textHeight 和下面的 descent 值。

外部设置数据源 datas 后,重新绘制。

代码语言:javascript
复制
var datas: Collection<String>? = null  
        set(value) {  
            field = value  
            invalidate()  
        } 

首先要绘制文字,我是先计算控件的高度 measuredHeight 减去所有文字的高度加上中间 margin 的大小,如果大于 0,说明有空间绘制。

代码语言:javascript
复制
private fun getSpaceHeight() = if (datas.isNullOrEmpty()) measuredHeight.toFloat()  
    else  
        measuredHeight - datas!!.size * textHeight -  
                (datas!!.size - 1) * textVerticalMargin

然后看 onDraw 方法。

代码语言:javascript
复制
var textSelectedIndex = -1

override fun onDraw(canvas: Canvas?) {  
    super.onDraw(canvas)  
    if (datas.isNullOrEmpty()) return  
    if (getSpaceHeight() < 0) {  
        Toast.makeText(context, "SideBar分配的高度不够展示", Toast.LENGTH_SHORT).show()  
        return  
    }  

    // 因为下面为了统一计算,所以先减掉一个 margin
    var lastY = getSpaceHeight()/2f - textVerticalMargin;  
  
    datas?.forEachIndexed { index, data ->  
        if (index == textSelectedIndex) {  
            paint.color = textColorSelected  
        } else {  
            paint.color = textColor  
        }  
        // lastY 用于循环中确定文字最底部的坐标
        lastY += textVerticalMargin + textHeight  
        canvas?.drawText(data, measuredWidth/2f, lastY - fontDescent, paint)  
    }  
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-11-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档