Example usage for android.view Gravity AXIS_Y_SHIFT

List of usage examples for android.view Gravity AXIS_Y_SHIFT

Introduction

In this page you can find the example usage for android.view Gravity AXIS_Y_SHIFT.

Prototype

int AXIS_Y_SHIFT

To view the source code for android.view Gravity AXIS_Y_SHIFT.

Click Source Link

Document

Bits defining the vertical axis.

Usage

From source file:android.support.v7.widget.LinearLayoutCompat.java

/**
 * Measures the children when the orientation of this LinearLayout is set
 * to {@link #HORIZONTAL}./* w  w  w  . j ava 2  s. co m*/
 *
 * @param widthMeasureSpec Horizontal space requirements as imposed by the parent.
 * @param heightMeasureSpec Vertical space requirements as imposed by the parent.
 *
 * @see #getOrientation()
 * @see #setOrientation(int)
 * @see #onMeasure(int, int)
 */
void measureHorizontal(int widthMeasureSpec, int heightMeasureSpec) {
    mTotalLength = 0;
    int maxHeight = 0;
    int childState = 0;
    int alternativeMaxHeight = 0;
    int weightedMaxHeight = 0;
    boolean allFillParent = true;
    float totalWeight = 0;

    final int count = getVirtualChildCount();

    final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    final int heightMode = MeasureSpec.getMode(heightMeasureSpec);

    boolean matchHeight = false;
    boolean skippedMeasure = false;

    if (mMaxAscent == null || mMaxDescent == null) {
        mMaxAscent = new int[VERTICAL_GRAVITY_COUNT];
        mMaxDescent = new int[VERTICAL_GRAVITY_COUNT];
    }

    final int[] maxAscent = mMaxAscent;
    final int[] maxDescent = mMaxDescent;

    maxAscent[0] = maxAscent[1] = maxAscent[2] = maxAscent[3] = -1;
    maxDescent[0] = maxDescent[1] = maxDescent[2] = maxDescent[3] = -1;

    final boolean baselineAligned = mBaselineAligned;
    final boolean useLargestChild = mUseLargestChild;

    final boolean isExactly = widthMode == MeasureSpec.EXACTLY;

    int largestChildWidth = Integer.MIN_VALUE;

    // See how wide everyone is. Also remember max height.
    for (int i = 0; i < count; ++i) {
        final View child = getVirtualChildAt(i);

        if (child == null) {
            mTotalLength += measureNullChild(i);
            continue;
        }

        if (child.getVisibility() == GONE) {
            i += getChildrenSkipCount(child, i);
            continue;
        }

        if (hasDividerBeforeChildAt(i)) {
            mTotalLength += mDividerWidth;
        }

        final LinearLayoutCompat.LayoutParams lp = (LinearLayoutCompat.LayoutParams) child.getLayoutParams();

        totalWeight += lp.weight;

        if (widthMode == MeasureSpec.EXACTLY && lp.width == 0 && lp.weight > 0) {
            // Optimization: don't bother measuring children who are going to use
            // leftover space. These views will get measured again down below if
            // there is any leftover space.
            if (isExactly) {
                mTotalLength += lp.leftMargin + lp.rightMargin;
            } else {
                final int totalLength = mTotalLength;
                mTotalLength = Math.max(totalLength, totalLength + lp.leftMargin + lp.rightMargin);
            }

            // Baseline alignment requires to measure widgets to obtain the
            // baseline offset (in particular for TextViews). The following
            // defeats the optimization mentioned above. Allow the child to
            // use as much space as it wants because we can shrink things
            // later (and re-measure).
            if (baselineAligned) {
                final int freeSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
                child.measure(freeSpec, freeSpec);
            } else {
                skippedMeasure = true;
            }
        } else {
            int oldWidth = Integer.MIN_VALUE;

            if (lp.width == 0 && lp.weight > 0) {
                // widthMode is either UNSPECIFIED or AT_MOST, and this
                // child
                // wanted to stretch to fill available space. Translate that to
                // WRAP_CONTENT so that it does not end up with a width of 0
                oldWidth = 0;
                lp.width = LayoutParams.WRAP_CONTENT;
            }

            // Determine how big this child would like to be. If this or
            // previous children have given a weight, then we allow it to
            // use all available space (and we will shrink things later
            // if needed).
            measureChildBeforeLayout(child, i, widthMeasureSpec, totalWeight == 0 ? mTotalLength : 0,
                    heightMeasureSpec, 0);

            if (oldWidth != Integer.MIN_VALUE) {
                lp.width = oldWidth;
            }

            final int childWidth = child.getMeasuredWidth();
            if (isExactly) {
                mTotalLength += childWidth + lp.leftMargin + lp.rightMargin + getNextLocationOffset(child);
            } else {
                final int totalLength = mTotalLength;
                mTotalLength = Math.max(totalLength, totalLength + childWidth + lp.leftMargin + lp.rightMargin
                        + getNextLocationOffset(child));
            }

            if (useLargestChild) {
                largestChildWidth = Math.max(childWidth, largestChildWidth);
            }
        }

        boolean matchHeightLocally = false;
        if (heightMode != MeasureSpec.EXACTLY && lp.height == LayoutParams.MATCH_PARENT) {
            // The height of the linear layout will scale, and at least one
            // child said it wanted to match our height. Set a flag indicating that
            // we need to remeasure at least that view when we know our height.
            matchHeight = true;
            matchHeightLocally = true;
        }

        final int margin = lp.topMargin + lp.bottomMargin;
        final int childHeight = child.getMeasuredHeight() + margin;
        childState = ViewUtils.combineMeasuredStates(childState, ViewCompat.getMeasuredState(child));

        if (baselineAligned) {
            final int childBaseline = child.getBaseline();
            if (childBaseline != -1) {
                // Translates the child's vertical gravity into an index
                // in the range 0..VERTICAL_GRAVITY_COUNT
                final int gravity = (lp.gravity < 0 ? mGravity : lp.gravity) & Gravity.VERTICAL_GRAVITY_MASK;
                final int index = ((gravity >> Gravity.AXIS_Y_SHIFT) & ~Gravity.AXIS_SPECIFIED) >> 1;

                maxAscent[index] = Math.max(maxAscent[index], childBaseline);
                maxDescent[index] = Math.max(maxDescent[index], childHeight - childBaseline);
            }
        }

        maxHeight = Math.max(maxHeight, childHeight);

        allFillParent = allFillParent && lp.height == LayoutParams.MATCH_PARENT;
        if (lp.weight > 0) {
            /*
             * Heights of weighted Views are bogus if we end up
             * remeasuring, so keep them separate.
             */
            weightedMaxHeight = Math.max(weightedMaxHeight, matchHeightLocally ? margin : childHeight);
        } else {
            alternativeMaxHeight = Math.max(alternativeMaxHeight, matchHeightLocally ? margin : childHeight);
        }

        i += getChildrenSkipCount(child, i);
    }

    if (mTotalLength > 0 && hasDividerBeforeChildAt(count)) {
        mTotalLength += mDividerWidth;
    }

    // Check mMaxAscent[INDEX_TOP] first because it maps to Gravity.TOP,
    // the most common case
    if (maxAscent[INDEX_TOP] != -1 || maxAscent[INDEX_CENTER_VERTICAL] != -1 || maxAscent[INDEX_BOTTOM] != -1
            || maxAscent[INDEX_FILL] != -1) {
        final int ascent = Math.max(maxAscent[INDEX_FILL], Math.max(maxAscent[INDEX_CENTER_VERTICAL],
                Math.max(maxAscent[INDEX_TOP], maxAscent[INDEX_BOTTOM])));
        final int descent = Math.max(maxDescent[INDEX_FILL], Math.max(maxDescent[INDEX_CENTER_VERTICAL],
                Math.max(maxDescent[INDEX_TOP], maxDescent[INDEX_BOTTOM])));
        maxHeight = Math.max(maxHeight, ascent + descent);
    }

    if (useLargestChild && (widthMode == MeasureSpec.AT_MOST || widthMode == MeasureSpec.UNSPECIFIED)) {
        mTotalLength = 0;

        for (int i = 0; i < count; ++i) {
            final View child = getVirtualChildAt(i);

            if (child == null) {
                mTotalLength += measureNullChild(i);
                continue;
            }

            if (child.getVisibility() == GONE) {
                i += getChildrenSkipCount(child, i);
                continue;
            }

            final LinearLayoutCompat.LayoutParams lp = (LinearLayoutCompat.LayoutParams) child
                    .getLayoutParams();
            if (isExactly) {
                mTotalLength += largestChildWidth + lp.leftMargin + lp.rightMargin
                        + getNextLocationOffset(child);
            } else {
                final int totalLength = mTotalLength;
                mTotalLength = Math.max(totalLength, totalLength + largestChildWidth + lp.leftMargin
                        + lp.rightMargin + getNextLocationOffset(child));
            }
        }
    }

    // Add in our padding
    mTotalLength += getPaddingLeft() + getPaddingRight();

    int widthSize = mTotalLength;

    // Check against our minimum width
    widthSize = Math.max(widthSize, getSuggestedMinimumWidth());

    // Reconcile our calculated size with the widthMeasureSpec
    int widthSizeAndState = ViewCompat.resolveSizeAndState(widthSize, widthMeasureSpec, 0);
    widthSize = widthSizeAndState & ViewCompat.MEASURED_SIZE_MASK;

    // Either expand children with weight to take up available space or
    // shrink them if they extend beyond our current bounds. If we skipped
    // measurement on any children, we need to measure them now.
    int delta = widthSize - mTotalLength;
    if (skippedMeasure || delta != 0 && totalWeight > 0.0f) {
        float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;

        maxAscent[0] = maxAscent[1] = maxAscent[2] = maxAscent[3] = -1;
        maxDescent[0] = maxDescent[1] = maxDescent[2] = maxDescent[3] = -1;
        maxHeight = -1;

        mTotalLength = 0;

        for (int i = 0; i < count; ++i) {
            final View child = getVirtualChildAt(i);

            if (child == null || child.getVisibility() == View.GONE) {
                continue;
            }

            final LinearLayoutCompat.LayoutParams lp = (LinearLayoutCompat.LayoutParams) child
                    .getLayoutParams();

            float childExtra = lp.weight;
            if (childExtra > 0) {
                // Child said it could absorb extra space -- give him his share
                int share = (int) (childExtra * delta / weightSum);
                weightSum -= childExtra;
                delta -= share;

                final int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
                        getPaddingTop() + getPaddingBottom() + lp.topMargin + lp.bottomMargin, lp.height);

                // TODO: Use a field like lp.isMeasured to figure out if this
                // child has been previously measured
                if ((lp.width != 0) || (widthMode != MeasureSpec.EXACTLY)) {
                    // child was measured once already above ... base new measurement
                    // on stored values
                    int childWidth = child.getMeasuredWidth() + share;
                    if (childWidth < 0) {
                        childWidth = 0;
                    }

                    child.measure(MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY),
                            childHeightMeasureSpec);
                } else {
                    // child was skipped in the loop above. Measure for this first time here
                    child.measure(MeasureSpec.makeMeasureSpec(share > 0 ? share : 0, MeasureSpec.EXACTLY),
                            childHeightMeasureSpec);
                }

                // Child may now not fit in horizontal dimension.
                childState = ViewUtils.combineMeasuredStates(childState,
                        ViewCompat.getMeasuredState(child) & ViewCompat.MEASURED_STATE_MASK);
            }

            if (isExactly) {
                mTotalLength += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin
                        + getNextLocationOffset(child);
            } else {
                final int totalLength = mTotalLength;
                mTotalLength = Math.max(totalLength, totalLength + child.getMeasuredWidth() + lp.leftMargin
                        + lp.rightMargin + getNextLocationOffset(child));
            }

            boolean matchHeightLocally = heightMode != MeasureSpec.EXACTLY
                    && lp.height == LayoutParams.MATCH_PARENT;

            final int margin = lp.topMargin + lp.bottomMargin;
            int childHeight = child.getMeasuredHeight() + margin;
            maxHeight = Math.max(maxHeight, childHeight);
            alternativeMaxHeight = Math.max(alternativeMaxHeight, matchHeightLocally ? margin : childHeight);

            allFillParent = allFillParent && lp.height == LayoutParams.MATCH_PARENT;

            if (baselineAligned) {
                final int childBaseline = child.getBaseline();
                if (childBaseline != -1) {
                    // Translates the child's vertical gravity into an index in the range 0..2
                    final int gravity = (lp.gravity < 0 ? mGravity : lp.gravity)
                            & Gravity.VERTICAL_GRAVITY_MASK;
                    final int index = ((gravity >> Gravity.AXIS_Y_SHIFT) & ~Gravity.AXIS_SPECIFIED) >> 1;

                    maxAscent[index] = Math.max(maxAscent[index], childBaseline);
                    maxDescent[index] = Math.max(maxDescent[index], childHeight - childBaseline);
                }
            }
        }

        // Add in our padding
        mTotalLength += getPaddingLeft() + getPaddingRight();
        // TODO: Should we update widthSize with the new total length?

        // Check mMaxAscent[INDEX_TOP] first because it maps to Gravity.TOP,
        // the most common case
        if (maxAscent[INDEX_TOP] != -1 || maxAscent[INDEX_CENTER_VERTICAL] != -1
                || maxAscent[INDEX_BOTTOM] != -1 || maxAscent[INDEX_FILL] != -1) {
            final int ascent = Math.max(maxAscent[INDEX_FILL], Math.max(maxAscent[INDEX_CENTER_VERTICAL],
                    Math.max(maxAscent[INDEX_TOP], maxAscent[INDEX_BOTTOM])));
            final int descent = Math.max(maxDescent[INDEX_FILL], Math.max(maxDescent[INDEX_CENTER_VERTICAL],
                    Math.max(maxDescent[INDEX_TOP], maxDescent[INDEX_BOTTOM])));
            maxHeight = Math.max(maxHeight, ascent + descent);
        }
    } else {
        alternativeMaxHeight = Math.max(alternativeMaxHeight, weightedMaxHeight);

        // We have no limit, so make all weighted views as wide as the largest child.
        // Children will have already been measured once.
        if (useLargestChild && widthMode != MeasureSpec.EXACTLY) {
            for (int i = 0; i < count; i++) {
                final View child = getVirtualChildAt(i);

                if (child == null || child.getVisibility() == View.GONE) {
                    continue;
                }

                final LinearLayoutCompat.LayoutParams lp = (LinearLayoutCompat.LayoutParams) child
                        .getLayoutParams();

                float childExtra = lp.weight;
                if (childExtra > 0) {
                    child.measure(MeasureSpec.makeMeasureSpec(largestChildWidth, MeasureSpec.EXACTLY),
                            MeasureSpec.makeMeasureSpec(child.getMeasuredHeight(), MeasureSpec.EXACTLY));
                }
            }
        }
    }

    if (!allFillParent && heightMode != MeasureSpec.EXACTLY) {
        maxHeight = alternativeMaxHeight;
    }

    maxHeight += getPaddingTop() + getPaddingBottom();

    // Check against our minimum height
    maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());

    setMeasuredDimension(widthSizeAndState | (childState & ViewCompat.MEASURED_STATE_MASK),
            ViewCompat.resolveSizeAndState(maxHeight, heightMeasureSpec,
                    (childState << ViewCompat.MEASURED_HEIGHT_STATE_SHIFT)));

    if (matchHeight) {
        forceUniformHeight(count, widthMeasureSpec);
    }
}