我想在 LudoBoard 上绘制 LudoDeck。我创建了一个自定义视图组并禁用了 willNotDraw
并设置了子视图的位置和大小,但它在某种程度上没有呈现到屏幕上。我在 logcat 中看到了 LudoDeck onDraw
的日志,但我不确定为什么它没有绘制,是不是因为我没有正确设置视图大小?
谁能帮我弄清楚我的错误在哪里?谢谢。
LudoBoard.kt
package io.github.andraantariksa.ludo
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
const val RATIO = 1.0f
class LudoBoard(context: Context, attributeSet: AttributeSet):
ViewGroup(context, attributeSet) {
private val ludoPawnsInLane = arrayOf<LudoPawn>()
private val totalGridToTarget = 6
private var gridSideSize = 0F
private val colors = arrayOf(Color.RED, Color.BLUE, Color.YELLOW, Color.GREEN)
private val deck = arrayOf<LudoDeck>(
LudoDeck(context))
init {
setWillNotDraw(false)
deck.forEach {
addView(it)
}
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
var width = measuredWidth
var height = measuredHeight
val widthWithoutPadding = width - paddingLeft - paddingRight
val heightWithoutPadding = height - paddingTop - paddingBottom
val maxWidth = (heightWithoutPadding * RATIO).toInt()
val maxHeight = (widthWithoutPadding / RATIO).toInt()
if (widthWithoutPadding > maxWidth) {
width = maxWidth + paddingLeft + paddingRight
} else {
height = maxHeight + paddingTop + paddingBottom
}
gridSideSize = width / (totalGridToTarget * 2 + 3).toFloat()
val deckSideSize = gridSideSize * 6F
deck.forEach {
it.measure(deckSideSize.toInt(), deckSideSize.toInt())
it.x = 0F
it.y = 0F
}
setMeasuredDimension(width, height)
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
// some code to draw the board
}
}
LudoDeck.kt
package io.github.andraantariksa.ludo
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.View
class LudoDeck(context: Context): View(context) {
private var totalPawn = 4
init {
setWillNotDraw(false)
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec)
}
override fun onDraw(canvas: Canvas) {
Log.d("zzzzz", "Draw")
val p = Paint()
p.color = Color.BLACK
val rect = Rect(0, 0, measuredWidth, measuredHeight)
canvas.drawRect(rect, p)
}
}
答案 0 :(得分:1)
所以基本上我稍微调整了你的代码,并在这个过程中也学习了 ViewGroups。谢谢!
我已经评论了代码中所做更改的解释,您可以参考,如果有任何疑问,请随时提问..
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.ViewGroup
const val RATIO = 1.0f
class LudoBoard1(context: Context, attributeSet: AttributeSet):
ViewGroup(context, attributeSet) {
// private val ludoPawnsInLane = arrayOf<LudoPawn>()
private val totalGridToTarget = 6
private var gridSideSize = 0F
private val colors = arrayOf(Color.RED, Color.BLUE, Color.YELLOW, Color.GREEN)
private val deck = arrayOf<LudoDeck>(
LudoDeck(context, attributeSet), LudoDeck(context, attributeSet))
init {
//setting this will call the onDraw method of the viewGroup. If we just want to treat this as a container
//then set this as 'true'. This way it will not draw anything.
setWillNotDraw(false)
//Add all your custom views here in the beginning.
deck.forEach {
addView(it)
}
}
/**
* This method is used to measure the size of the view itself and also the size of the children.
* Here we calculate the size and allocate it to the children also by calling their "measure()"
* method.
* It's extremely important to call the "setMeasuredDimension()" at the end as this method will
* allocated the measured width and the height.
*/
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
var width = measuredWidth
var height = measuredHeight
val widthWithoutPadding = width - paddingLeft - paddingRight
val heightWithoutPadding = height - paddingTop - paddingBottom
val maxWidth = (heightWithoutPadding * RATIO).toInt()
val maxHeight = (widthWithoutPadding / RATIO).toInt()
if (widthWithoutPadding > maxWidth) {
width = maxWidth + paddingLeft + paddingRight
} else {
height = maxHeight + paddingTop + paddingBottom
}
gridSideSize = width / (totalGridToTarget * 2 + 3).toFloat()
val deckSideSize = gridSideSize * 6F
deck.forEach {
it.measure(deckSideSize.toInt(), deckSideSize.toInt())
}
setMeasuredDimension(width, height)
}
/**
* For a viewGroup, its better if we don't draw anything, but still if we have to, then we can.
* The view group is designed as a container where it determines it's own size, it's children's size
* and their positions.
*/
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
// some code to draw the board
}
/**
* This is the method where we calculate the positions for every child. Here we determine the
* starting and ending point for every child element of this viewGroup.
*/
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
/*
Here you will determine the position for every child. Calculate the left top right bottom for every child
and allocate it to the layout.
For now, i am just positioning the ludo deck besides each other.
*/
var previousXStartPoint = 0
deck.forEachIndexed { index, it ->
it.layout(previousXStartPoint , 0, previousXStartPoint.plus(it.measuredWidth), (it.measuredHeight))
previousXStartPoint = it.right + 20
}
}
}
这是 LudoDeck 类:
class LudoDeck(context: Context, attrs: AttributeSet?): View(context, attrs) {
private var totalPawn = 4
private val rect = Rect(0, 0, 50, 50)
private val p = Paint()
/*
As we are drawing something in this view, it's appropriate to set call this method in the beginning.
*/
init {
setWillNotDraw(false)
}
/**
* Its advised not to initialize anything in the onMeasure() method. So, we have already initialized
* the rect in the beginning and now we will just update its params.
*/
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
rect.right = widthMeasureSpec
rect.bottom = heightMeasureSpec
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec)
}
/**
* Its also advised not to initialize anything in onDraw() method, so we have already created the paint
* object. Here we simply draw!
*/
override fun onDraw(canvas: Canvas) {
p.color = Color.BLACK
canvas.drawRect(rect, p)
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
//Uncomment to check whether the dims set in onLayout of Ludo Board are properly allocated. :)
//Log.e("ludoDeck", "left: $left, top: $top, right: $right, bottom: $bottom")
}
最后,我能够理解一些事情并使其工作的来源是:https://academy.realm.io/posts/360andev-huyen-tue-dao-measure-layout-draw-repeat-custom-views-and-viewgroups-android/
告诉我结果如何!