自定义表格控件 FormView

最近项目用到表格,所以自己画了一个。看下图:

自定义表格控件 FormView_第1张图片

自定义表格控件 FormView_第2张图片

自定义表格控件 FormView_第3张图片

 

 

下面具体实现(Kotlin):

首先我们需要确定传入的数据,这里我选择传入ArrayList,即每个String对应一个cell,根据传入List的Size和设置的列数计算出行数:

 

class FormView (context: Context?, attrs: AttributeSet?) : View(context, attrs) {

    // 表格行数
    private var rowNum = 0
    // 表格列数
    private var colNum = 2
    // 表格数据
    private var mDataList = ArrayList()

    init {
        val ta = context!!.obtainStyledAttributes(attrs, R.styleable.FormView)
        this.rowNum = ta.getInt(R.styleable.FormView_rowNum, 0)
        this.colNum = ta.getInt(R.styleable.FormView_colNum, 2)
        ta.recycle()
    }

    /**
     * 设置表格数据
     */
    fun setDataList(dataList: ArrayList) {
        this.mDataList.clear()
        this.mDataList.addAll(dataList)
        this.rowNum = if (mDataList.size % colNum == 0) mDataList.size/colNum else mDataList.size/colNum + 1
        invalidate()
    }
}


如此我们就知道表格的行数和列数了,但是我们知道自定义View继承View的时候,默认宽高是 match_parent,所以我们还需要动态设置FormView的高度(一般宽度都会设置match_parent的吧):

 

 

@SuppressLint("DrawAllocation")
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        //计算总高度
        var overHeight = 0f
        for (i in 0 until rowNum){
            val strArray = ArrayList()
            (0 until colNum)
                    .filter { (i * colNum + it) < mDataList.size }
                    .mapTo(strArray) { mDataList[i * colNum + it] }
            //记录最后一行最底部位置
            overHeight += getRowHeight(strArray)
        }
        setMeasuredDimension(getDefaultSize(suggestedMinimumWidth, widthMeasureSpec), overHeight.toInt())
}

 

在onMeasure方法里面计算出它的总高度(默认无数据的时候高度为0),getRowHeight() 方法会计算出每一行的高度,进行累加得到总高度。在getRowHeight()方法是怎么计算行高的呢?比如我们每一行有2列,getRowHeight()会根据字符长度和列宽先把每一列的列高计算出来:如果字符长度大于列宽,则 行高 = 字符高度 * (字符长度/列宽)或者 行高 = 字符高度 * (字符长度/列宽 + 1);如果字符长度小于列宽, 则 行高 = 字符高度。然后返回最大的列高作为此行的行高:

 

 

/**
 * 计算每一行最大高度
 */
private fun getRowHeight(strList: ArrayList): Float {
        var mFormRowHeight = 0f
        for (text in strList) {
            val textWidth = getTextWidthAndHeight(text)[0]
            val textHeight = getTextWidthAndHeight(text)[1]
            val formRowHeight: Float = if (textWidth <= measuredWidth/colNum - textPadding*2) {
                (textPadding*2 + textHeight).toFloat()
            } else {
                val num: Int = textWidth / (measuredWidth/colNum - textPadding*2)
                if (textWidth % (measuredWidth/colNum - textPadding*2) == 0) {
                    (textPadding*2 + textHeight * num).toFloat()
                } else {
                    (textPadding*2 + textHeight * (num + 1)).toFloat()
                }
            }
            if (mFormRowHeight < formRowHeight) {
                mFormRowHeight = formRowHeight
            }
        }

        return mFormRowHeight
}


以上,再使用StatixLayout让文字自动换行,就达到动态行高和FormView高度的效果了。

 

后记:setDataList() 方法设置数据的时候我们需要对 View进行重绘,上面调用的是 invalidate() 方法,而 invalidate() 方法是只有draw流程可以得到执行,不会再次执行measure和layout流程的,所以这里我们需要更改为 requestLayout() 方法。

 

下载地址:

  GitHub: https://github.com/zhumj/FormView.git
  CSDN: http://download.csdn.net/download/zhumj_zhumj/10131026

 

你可能感兴趣的:(Android)