我在自定义视图中有两种方法,onMeasure和onDraw。我有一个函数,用于从源设置数据并使用使视图功能无效来重绘视图。我使用onMeasure来获取计算所需的视图宽度。但是,当我使用无效函数onDraw首先被调用,然后我的onMeasure被调用。因此,我的视图宽度始终为0px。

我尝试过调用requestLayout(),然后使invalidate()重绘视图

override fun onDraw(canvas: Canvas?) {
    super.onDraw(canvas)

    val pointY = 15.px.toFloat()
    var pointX = oneCellWidth.toFloat() / 2f

    totalDays.forEach { day ->
        val isWorkedDay = workedDays.filter { it.date == day.date }.size
        if (isWorkedDay > 0) {
            canvas?.drawCircle(pointX, pointY, 8f, circlePaint)
        }
        pointX += oneCellWidth
    }
}

fun submitData(totalDays: List<Day>, workedDays: List<WorkedDateAndTime>, color: Int) {
    this.totalDays = totalDays
    this.workedDays = workedDays
    circlePaint.color = color
    oneCellWidth = viewWidth / totalDays.size
    invalidate()
}

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec)

    val widthMode = MeasureSpec.getMode(widthMeasureSpec)
    val widthSize = MeasureSpec.getSize(widthMeasureSpec)

    if (widthMode == MeasureSpec.EXACTLY) {
        viewWidth = widthSize

    }
}


需要viewWidth不具有视图宽度值。

最佳答案

我想问题正在发生,因为您在调用viewWidth之前正在阅读View.invalidate()。因此,当您读取viewWidth时,它仍然具有旧值。

因此,我建议进行以下更改:

override fun onDraw(canvas: Canvas?) {
    super.onDraw(canvas)

    oneCellWidth = viewWidth / totalDays.size // Add this
    val pointY = 15.px.toFloat()
    var pointX = oneCellWidth.toFloat() / 2f

    totalDays.forEach { day ->
        val isWorkedDay = workedDays.filter { it.date == day.date }.size
        if (isWorkedDay > 0) {
            canvas?.drawCircle(pointX, pointY, 8f, circlePaint)
        }
        pointX += oneCellWidth
    }
}

fun submitData(totalDays: List<Day>, workedDays: List<WorkedDateAndTime>, color: Int) {
    this.totalDays = totalDays
    this.workedDays = workedDays
    circlePaint.color = color
    // oneCellWidth = viewWidth / totalDays.size --> Remove this
    requestLayout() // Add this. invalidate only request re-draw. requestLayout will request to re-measure
    invalidate()
}

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec)

    val widthMode = MeasureSpec.getMode(widthMeasureSpec)
    val widthSize = MeasureSpec.getSize(widthMeasureSpec)

    if (widthMode == MeasureSpec.EXACTLY) {
        viewWidth = widthSize
    }
}


这样,您可以避免在重新执行viewWidth之前读取onMeasure的问题。进行这些更改后,您将在viewWidth期间读取onDraw,这总是在onMeasure之后执行(当然,如果您调用requestLayout()

10-04 19:34