我应该在android中使用getMeasuredState()吗?

时间:2015-12-10 15:39:23

标签: android android-layout android-linearlayout measure

我的布局有一个复杂的自定义逻辑,它依赖于子状态:如果任何一个孩子没有足够的空间,则要求每个孩子使用其自定义压缩状态。

我的预期

正如 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状态(如果是,那么为什么)??

1 个答案:

答案 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()方法。

我不太确定你在用例中尝试用这些方法实现的目标是诚实的。