我的理解是LinearLayout应该分配松弛 (额外空间)和/或收缩(负额外空间) 根据孩子的布局重量。 这看起来像我期望的那样松弛,但不是缩小。
以下android活动演示。 它显示了9列(垂直LinearLayouts),具有不同的度数 拥挤。 9列中的每一列都有两个孩子:
每个子列的权重与单选按钮的数量成正比 在它(3或2)中,子列中每个单选按钮的权重为1。
我选择了这些权重以分配列的额外空间 (孙女)(孙女按钮)平等(负面或正面), 这样,给定列中的所有5个单选按钮的大小都相同。
它看似按预期用于松弛(红色列,在右侧), 但不是缩小(蓝色列,左侧),如下所示 屏幕截图显示(启用了开发人员选项“显示布局边界”)。 在最拥挤(最左边)的列中,差异最明显, 其中前三个单选按钮最终比它们的两个堂兄小得多。
这是LinearLayout的预期行为吗? 或者它是LinearLayout中的错误?或者我的程序中有错误?
这是程序列表(在Kotlin中):
// app/src/main/java/com/example/donhatch/linearlayoutweightsquestionactivity/MainActivity.kt
// Simple activity to test LinearLayout's slack/shrinkage distribution behavior.
package com.example.donhatch.linearlayoutweightsquestionactivity
import android.graphics.Color
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.widget.LinearLayout
import android.widget.RadioButton
import android.widget.RadioGroup
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val c = applicationContext
val WC = LinearLayout.LayoutParams.WRAP_CONTENT
setContentView(object: LinearLayout(c) {init{
// A row of 9 columns, from crowded to uncrowded.
orientation = HORIZONTAL
val columnHeights = arrayOf(
200, 300, 400, 500, // crowded
WC, // just right (comes out 5*112 = 560)
600, 700, 800, 900 // uncrowded
)
for (columnHeight in columnHeights) {
addView(object: LinearLayout(c) {init{
// A column with two child columns (radio groups).
orientation = VERTICAL
setBackgroundColor(when {
columnHeight==WC -> Color.WHITE
columnHeight<560 -> Color.argb(255,224,224,255) // crowded: blue
else -> Color.argb(255,255,224,224) // uncrowded: red
})
addView(object: RadioGroup(c) {init{
// First child column: three radio buttons.
orientation = VERTICAL
for (i in 0 until 3) {
addView(object: RadioButton(c) {init{
text = 'A'.plus(i) + " " // "A", "B", ...
}}, LayoutParams(WC, WC, 1.0f))
}
}}, LayoutParams(WC, WC, 3.0f)) // weight=3 for 3 children
addView(object: RadioGroup(c) {init{
// Second child column: two radio buttons.
orientation = VERTICAL
for (i in 0 until 2) {
addView(object: RadioButton(c) {init{
text = '0'.plus(i) + " " // "0", "1", ...
}}, LayoutParams(WC, WC, 1.0f))
}
}}, LayoutParams(WC, WC, 2.0f)) // weight=2 for 2 children
}}, LayoutParams(WC, columnHeight))
} // for columnHeight
}}) // setContentView
} // onCreate
} // class MainActivity
答案 0 :(得分:1)
我跟踪了LinearLayouts和RadioButtons中对onMeasure的调用, 我相信我明白现在发生了什么。基于此,我相信这是LinearLayout中的一个错误。
关注高度为300的列,其中有3 + 2个单选按钮,以下是计算结果。
使用onMeasure()
调用父列的heightSpec = EXACTLY 300
。
它问两个孩子他们想要多大,被限制为只不过是自己的
确切知道身高300:
onMeasure()
调用第一个子列的heightSpec = AT_MOST 300
。
第一个子列的总首选高度为336 = 3 * 112(3个单选按钮,每个按钮高度为112像素)超出预算,
所以它回答它希望它的高度是允许的最大值,即300。onMeasure()
调用第二个子列的heightSpec = AT_MOST 300
。
第二个子列的总首选高度为224 = 2 * 112(2个单选按钮),这在预算范围内,
所以它回复说它希望有高度224。因此,孩子们报告的总首选大小是300 + 224 = 524,这个大小超过224像素。 因此,它将收缩224分配给两个孩子,其比例为3:2; 也就是说,第一个孩子收缩(3/5)* 224 = 134.4(四舍五入到134)和 第二个孩子收缩(2/5)* 224 = 89.6(四舍五入到90)。 因此,两个子列分别达到300-134 = 166和224-90 = 134的高度。 这两个子栏目现在告诉他们的高度,让他们分发给他们的孩子:
onMeasure()
调用第一个孩子的heightSpec="EXACTLY 166"
。
它将这个高度166公平分配给它的三个孩子,使它们的高度为56,55,55。onMeasure()
调用第二个孩子的heightSpec="EXACTLY 134"
。
它将高度134分配给它的两个孩子,使它们的高度达到67,67。因此,列中5个单选按钮的最终高度为56,55,55,67,67; 即前三个小于后两个。这解释了不公平的分配。
在我看来,在向孩子们询问什么样的高度时,错误是指定AT_MOST 300
他们希望:MeasureSpec
模式AT_MOST
既不需要也不适合,
并且它导致收缩的不公平分布。 MeasureSpec
模式UNSPECIFIED
本来是一个更好的选择:它最终会在没有任何限制的情况下得出正确的答案
违规。
让我们再次进行计算,但使用UNSPECIFIED
代替AT_MOST 300
当问孩子们他们想要什么样的高度时。
使用onMeasure()
调用父列的heightSpec = EXACTLY 300
。
它问两个孩子他们有多大,没有任何限制:
onMeasure()
调用第一个子列的heightSpec = UNSPECIFIED
。
第一个子列回复它想要高度336 = 3 * 112(3个单选按钮)。onMeasure()
调用第二个子列的heightSpec = UNSPECIFIED
第二个子列回复它希望高度224 = 2 * 112(2个单选按钮)。所以孩子们的首选大小是336 + 224 = 560,这个数字太大了260像素。 因此,它将收缩率260分配给两个孩子,其比例为3:2; 也就是说,第一个孩子收缩(3/5)* 260 = 156和 第二个孩子收缩(2/5)* 260 = 104。 因此,两个子列分别达到336-156 = 180和224-104 = 120的高度。 这两个子栏目现在告诉他们的高度,并告诉他们的后代:
onMeasure()
调用第一个孩子的heightSpec = EXACTLY 180
。
它将高度180分配给它的三个孩子,使它们的高度达到60,60,60。onMeasure()
调用第二个孩子的heightSpec = EXACTLY 120
它将高度120公平地分配给它的两个孩子,使它们的高度为60,60。因此,列中5个单选按钮的最终高度为60,60,60,60,60, 这是理想的行为。