我正在创建一个自定义ViewGroup。 如果我将自定义ViewGroup添加到布局而未指定LayoutParams(如下所示),则会正确显示:
...
MyCustomViewGroup myViewGroup = new MyCustomViewGroup(this);
myRelativeLayout.addView(myViewGroup);
...
如果我指定LayoutParams并将宽度设置为MATCH_PARENT并将高度设置为WRAP_CONTENT(如下所示),则不会显示:
...
MyCustomViewGroup myViewGroup = new MyCustomViewGroup(this);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
myRelativeLayout.addView(myViewGroup, params);
...
我为两种情况都运行了Debug。
情景1
如果我没有指定任何LayoutParams,则子视图会正确测量,当方法遍历所有子视图以确定最大高度时,child.getMeasuredHeight()
每次都会返回正确的值。
情景2
如果我将LayoutParams指定为宽度为MATCH_PARENT,高度指定为WRAP_CONTENT,则系统会通过onMeasure执行两次传递,如下所述。
通过1
widthSpecMode =完全
width = widthSpecSize = 758,这是父RelativeLayout的宽度
heightSpecMode =确实是
height = heightSpecSize = 1055这是父RelativeLayout
通过2
widthSpecMode =完全
width = widthSpecSize = 758,这是父RelativeLayout的宽度
heightSpecMode = AT_MOST
然后,该方法遍历所有子视图以确定最大高度,但child.getMeasuredHeight()
每次返回0。
子视图有几个ImageButtons和一个TextView。它们都有内容,并且在第一个场景中正确显示了内容。 为什么在第二种情况下它的高度为0,我该如何解决呢?
`' 我写了一个简化的测试应用程序来重现问题。 所有必要的代码如下所示。如果有人想尝试,你可以简单地剪切和粘贴。
MainActivity.java
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RelativeLayout rootLayout = (RelativeLayout)findViewById(R.id.LayoutRoot);
// Create an instance of MyViewGroup
MyViewGroup viewGroupOne = new MyViewGroup(this);
viewGroupOne.setId(1);
rootLayout.addView(viewGroupOne);
// Create a second instance and set layout width and height both to WRAP_CONTENT
MyViewGroup viewGroupTwo = new MyViewGroup(this);
viewGroupTwo.setId(2);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.BELOW, 1);
rootLayout.addView(viewGroupTwo, params);
// Create a third Instance. Set layout width to MATCH_PARENT and height to WRAP_CONTENT
MyViewGroup viewGroupThree = new MyViewGroup(this);
params = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.BELOW, 2);
rootLayout.addView(viewGroupThree, params);
}
}
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/LayoutRoot"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
</RelativeLayout>
MyViewGroup.java
public class MyViewGroup extends ViewGroup {
private static int instanceCounter;
public MyViewGroup(Context context) {
super(context);
instanceCounter++;
// Add a TextView
TextView textView = new TextView(context);
String text = "Instance " + instanceCounter;
textView.setText(text);
addView(textView);
// Add an ImageView
ImageView imageView = new ImageView(context);
imageView.setImageResource(android.R.drawable.ic_menu_add);
addView(imageView);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int childCount = getChildCount();
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
int width = 0;
int height = 0;
int childState = 0;
// Measure Width
if (widthSpecMode == MeasureSpec.EXACTLY) {
width = widthSpecSize;
} else {
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
measureChild(child, widthMeasureSpec, heightMeasureSpec);
width += child.getMeasuredWidth();
}
}
}
if (widthSpecMode == MeasureSpec.AT_MOST) {
width = Math.min(width, widthSpecSize);
}
// Measure Height
if (heightSpecMode == MeasureSpec.EXACTLY) {
height = heightSpecSize;
} else {
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
height = Math.max(height, child.getMeasuredHeight());
}
}
}
if (heightSpecMode == MeasureSpec.AT_MOST) {
height = Math.min(height, heightSpecSize);
}
// Combine child states
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
childState = combineMeasuredStates(childState, child.getMeasuredState());
}
}
// Check against minimum width and height
width = Math.max(width, getSuggestedMinimumWidth());
height = Math.max(height, getSuggestedMinimumHeight());
// Report final dimensions
setMeasuredDimension(resolveSizeAndState(width, widthMeasureSpec, childState),
resolveSizeAndState(height, heightMeasureSpec, childState << MEASURED_HEIGHT_STATE_SHIFT));
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int childCount = getChildCount();
int leftPos = 0;
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
final int childWidth = child.getMeasuredWidth();
if (child.getVisibility() != GONE) {
child.layout(leftPos, 0, leftPos + childWidth, getMeasuredHeight());
leftPos += childWidth;
}
}
}
}
答案 0 :(得分:8)
ok soit似乎你忘了调用measureChild(child,widthMeasureSpec,heightMeasureSpec);在onMeasure中计算高度时