我的布局有一个复杂的自定义逻辑,它依赖于子状态:如果任何一个孩子没有足够的空间,则要求每个孩子使用其自定义压缩状态。
我的预期
正如 getMeasuredState ()所说:
仅返回getMeasuredWidthAndState()和getMeasuredHeightAndState()的状态位,合并为一个整数。宽度分量位于常规位MEASURED_STATE_MASK中,高度分量位于移位位MEASURED_HEIGHT_STATE_SHIFT>> MEASURED_STATE_MASK。
我想,我们可以在每次测量后询问每个孩子是否受到测量状态的限制。所以我的布局实现从LinearLayout
扩展并添加以下内容:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
expand();
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (isTooSmall()) {
condense();
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
/**
* return true if any child has TOO_SMALL flag
*/
private boolean isTooSmall(){
for (int i = 0; i < getChildCount(); i++){
View child = getChildAt(i);
if (child != null){
//I'm interested in width only
int measuredState = child.getMeasuredState() & MEASURED_STATE_TOO_SMALL;
if (measuredState != 0) return true;
}
}
return false;
}
结果是什么
child.getMeasuredState()
返回0,无论是否被裁剪(布局具有准确的宽度)。我的所有子视图都从TextView
扩展而来,并查看源代码,我发现TextView
根本没有使用测量状态位!为什么会这样,我应该从哪里知道?
问题
我们何时应该依赖MEASURED_STATE_MASK?如果甚至框架组件(api 23)都可以轻易忽略它,我们怎么能确定它会起作用呢?我想完全不能保证任何View
,布局中的真实状态和getMeasuredState()
的结果是相同的。或者只是TextView
类似的类,假设永远不会有TOO_SMALL
状态(如果是,那么为什么)??
答案 0 :(得分:1)
也许它返回0因为onLayout()
和onMeasure()
方法被错误地实现了?
当它们没有正确实现时,需要一段时间查看它的实际大小 - 如果它甚至'找到'它并将值从0更改为其他东西。
尝试以下两种方法:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int desiredWidth = 100;
int desiredHeight = 100;
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width;
int height;
//Measure Width
if(widthMode == MeasureSpec.EXACTLY) {
//Must be this size
width = widthSize;
} else if(widthMode == MeasureSpec.AT_MOST) {
//Can't be bigger than...
width = Math.min(desiredWidth, widthSize);
} else {
//Be whatever you want
width = desiredWidth;
}
//Measure Height
if(heightMode == MeasureSpec.EXACTLY) {
//Must be this size
height = heightSize;
} else if(heightMode == MeasureSpec.AT_MOST) {
//Can't be bigger than...
height = Math.min(desiredHeight, heightSize);
} else {
//Be whatever you want
height = desiredHeight;
}
//MUST CALL THIS
setMeasuredDimension(width, height);
linear_rootLayout.measure(MeasureSpec.makeMeasureSpec(width, widthMode), MeasureSpec.makeMeasureSpec(height, heightMode));
measureChildren(MeasureSpec.makeMeasureSpec(width, widthMode), MeasureSpec.makeMeasureSpec(height, heightMode));
super.onMeasure(MeasureSpec.makeMeasureSpec(width, widthMode), MeasureSpec.makeMeasureSpec(height, heightMode));
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// TODO Auto-generated method stub
final int count = getChildCount();
int curWidth, curHeight, curLeft, curTop, maxHeight;
//get the available size of child view
int childLeft = this.getPaddingLeft();
int childTop = this.getPaddingTop();
int childRight = this.getMeasuredWidth() - this.getPaddingRight();
int childBottom = this.getMeasuredHeight() - this.getPaddingBottom();
int childWidth = childRight - childLeft;
int childHeight = childBottom - childTop;
maxHeight = 0;
curLeft = childLeft;
curTop = childTop;
//walk through each child, and arrange it from left to right
for(int i = 0; i < count; i++) {
View child = getChildAt(i);
if(child.getVisibility() != GONE) {
//Get the maximum size of the child
child.measure(MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.AT_MOST));
curWidth = child.getMeasuredWidth();
curHeight = child.getMeasuredHeight();
//wrap is reach to the end
if(curLeft + curWidth >= childRight) {
curLeft = childLeft;
curTop += maxHeight;
maxHeight = 0;
}
//do the layout
child.layout(curLeft, curTop, curLeft + curWidth, curTop + curHeight);
//store the max height
if(maxHeight < curHeight) maxHeight = curHeight;
curLeft += curWidth;
}
}
}
也许他们会为你改变一些东西。也许您还需要实施measure()
和layout()
方法。
我不太确定你在用例中尝试用这些方法实现的目标是诚实的。