Reputation: 93
I have two method in custom view, onMeasure and onDraw. I have a function that is used to set the data from the source and use invalidate the view function to redraw the view. I use the onMeasure to get the width of the view that is needed for my calculation. But when i use the invalidate function onDraw get called first and then my onMeasure gets called. Hence my view width is always 0px.
I have tried calling requestLayout() and then invalidate() to redraw the view
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
}
}
Need the viewWidth not to be have the view width value.
Upvotes: 2
Views: 717
Reputation: 18677
I guess the problem is happening because you are reading viewWidth
before calling View.invalidate()
. So, when you read the viewWidth
, it still has the old value.
So, I suggest following changes:
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
}
}
This way, you avoid the issue of reading viewWidth
before onMeasure
is re-executed. After those changes, you read viewWidth
during onDraw
which is always executed after onMeasure
(if you call requestLayout()
of course.
Upvotes: 2