Android 五种布局简单介绍

五种布局有: FrameLayout 、 LinearLayout、 AbsoluteLayout、RelativeLayout 、TableLayout

  • FrameLayout (框架布局)
    此布局是五种布局中最简单的布局,Android中并没有对Child View的摆布进行控制,这个布局中所有的控件都会默认出现在视图的左上角,我们可以使用android:layout_margin,andorid:layout_gravity等属性去控制子控件相对布局的位置。onLayout()源码如下:
  @Override    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {        layoutChildren(left, top, right, bottom, false /* no force left gravity */);    }    void layoutChildren(int left, int top, int right, int bottom, boolean forceLeftGravity) {        final int count = getChildCount();        final int parentLeft = getPaddingLeftWithForeground();        final int parentRight = right - left - getPaddingRightWithForeground();        final int parentTop = getPaddingTopWithForeground();        final int parentBottom = bottom - top - getPaddingBottomWithForeground();        for (int i = 0; i < count; i++) {            final View child = getChildAt(i);            if (child.getVisibility() != GONE) {                final LayoutParams lp = (LayoutParams) child.getLayoutParams();                final int width = child.getMeasuredWidth();                final int height = child.getMeasuredHeight();                int childLeft;                int childTop;                int gravity = lp.gravity;                if (gravity == -1) {                    gravity = DEFAULT_CHILD_GRAVITY;                }                final int layoutDirection = getLayoutDirection();                final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);                final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;                switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {                    case Gravity.CENTER_HORIZONTAL:                        childLeft = parentLeft + (parentRight - parentLeft - width) / 2 +                        lp.leftMargin - lp.rightMargin;                        break;                    case Gravity.RIGHT:                        if (!forceLeftGravity) {                            childLeft = parentRight - width - lp.rightMargin;                            break;                        }                    case Gravity.LEFT:                    default:                        childLeft = parentLeft + lp.leftMargin;                }                switch (verticalGravity) {                    case Gravity.TOP:                        childTop = parentTop + lp.topMargin;                        break;                    case Gravity.CENTER_VERTICAL:                        childTop = parentTop + (parentBottom - parentTop - height) / 2 +                        lp.topMargin - lp.bottomMargin;                        break;                    case Gravity.BOTTOM:                        childTop = parentBottom - height - lp.bottomMargin;                        break;                    default:                        childTop = parentTop + lp.topMargin;                }                child.layout(childLeft, childTop, childLeft + width, childTop + height);            }        }    }

对于子view只是对Gravity进行检查然后进行了布局。

  • LinearLayout(线性布局)
    一行或一列只控制一个控件的线性布局,所以当有很多空间需要一个界面列出来时,可以用LinearLayout布局。此布局有一个需要格外注意的属性android:orientation=”horizontal|vertical”重要源码如下:
  • android:orientation="horizontal时,说明你希望将水平方向的布局交给LinearLayout ,其子元素的android:layout_gravity="right|left" 等控制水平方向的gravity值都是被忽略的,此时LinearLayout中的子元素都是默认的按照水平从左向右来排,我们可以用android:layout_gravity="top|bottom"等gravity值来控制垂直展示。
  • 反之,可以知道 当android:orientation="vertical时,LinearLayout对其子元素展示上的的处理方式。

测量

    public static final int HORIZONTAL = 0;    public static final int VERTICAL = 1;   @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        if (mOrientation == VERTICAL) {            measureVertical(widthMeasureSpec, heightMeasureSpec);        } else {            measureHorizontal(widthMeasureSpec, heightMeasureSpec);        } /**     * Measures the children when the orientation of this LinearLayout is set     * to {@link #VERTICAL}.     *     * @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 measureVertical(int widthMeasureSpec, int heightMeasureSpec) {        mTotalLength = 0;        int maxWidth = 0;        int childState = 0;        int alternativeMaxWidth = 0;        int weightedMaxWidth = 0;        boolean allFillParent = true;        float totalWeight = 0;        final int count = getVirtualChildCount();        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);        boolean matchWidth = false;        boolean skippedMeasure = false;        final int baselineChildIndex = mBaselineAlignedChildIndex;        final boolean useLargestChild = mUseLargestChild;        int largestChildHeight = Integer.MIN_VALUE;        int consumedExcessSpace = 0;        int nonSkippedChildCount = 0;        // See how tall everyone is. Also remember max width.        for (int i = 0; i < count; ++i) {            final View child = getVirtualChildAt(i);            if (child == null) {                mTotalLength += measureNullChild(i);                continue;            }            if (child.getVisibility() == View.GONE) {               i += getChildrenSkipCount(child, i);               continue;            }            nonSkippedChildCount++;            if (hasDividerBeforeChildAt(i)) {                mTotalLength += mDividerHeight;            }            final LayoutParams lp = (LayoutParams) child.getLayoutParams();            totalWeight += lp.weight;            final boolean useExcessSpace = lp.height == 0 && lp.weight > 0;            if (heightMode == MeasureSpec.EXACTLY && useExcessSpace) {                // Optimization: don't bother measuring children who are only                // laid out using excess space. These views will get measured                // later if we have space to distribute.                final int totalLength = mTotalLength;                mTotalLength = Math.max(totalLength, totalLength + lp.topMargin + lp.bottomMargin);                skippedMeasure = true;            } else {                if (useExcessSpace) {                    // The heightMode is either UNSPECIFIED or AT_MOST, and                    // this child is only laid out using excess space. Measure                    // using WRAP_CONTENT so that we can find out the view's                    // optimal height. We'll restore the original height of 0                    // after measurement.                    lp.height = 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).                final int usedHeight = totalWeight == 0 ? mTotalLength : 0;                measureChildBeforeLayout(child, i, widthMeasureSpec, 0,                        heightMeasureSpec, usedHeight);                final int childHeight = child.getMeasuredHeight();                if (useExcessSpace) {                    // Restore the original height and record how much space                    // we've allocated to excess-only children so that we can                    // match the behavior of EXACTLY measurement.                    lp.height = 0;                    consumedExcessSpace += childHeight;                }                final int totalLength = mTotalLength;                mTotalLength = Math.max(totalLength, totalLength + childHeight + lp.topMargin +                       lp.bottomMargin + getNextLocationOffset(child));                if (useLargestChild) {                    largestChildHeight = Math.max(childHeight, largestChildHeight);                }            }            /**             * If applicable, compute the additional offset to the child's baseline             * we'll need later when asked {@link #getBaseline}.             */            if ((baselineChildIndex >= 0) && (baselineChildIndex == i + 1)) {               mBaselineChildTop = mTotalLength;            }            // if we are trying to use a child index for our baseline, the above            // book keeping only works if there are no children above it with            // weight.  fail fast to aid the developer.            if (i < baselineChildIndex && lp.weight > 0) {                throw new RuntimeException("A child of LinearLayout with index "                        + "less than mBaselineAlignedChildIndex has weight > 0, which "                        + "won't work.  Either remove the weight, or don't set "                        + "mBaselineAlignedChildIndex.");            }            boolean matchWidthLocally = false;            if (widthMode != MeasureSpec.EXACTLY && lp.width == LayoutParams.MATCH_PARENT) {                // The width of the linear layout will scale, and at least one                // child said it wanted to match our width. Set a flag                // indicating that we need to remeasure at least that view when                // we know our width.                matchWidth = true;                matchWidthLocally = true;            }            final int margin = lp.leftMargin + lp.rightMargin;            final int measuredWidth = child.getMeasuredWidth() + margin;            maxWidth = Math.max(maxWidth, measuredWidth);            childState = combineMeasuredStates(childState, child.getMeasuredState());            allFillParent = allFillParent && lp.width == LayoutParams.MATCH_PARENT;            if (lp.weight > 0) {                /*                 * Widths of weighted Views are bogus if we end up                 * remeasuring, so keep them separate.                 */                weightedMaxWidth = Math.max(weightedMaxWidth,                        matchWidthLocally ? margin : measuredWidth);            } else {                alternativeMaxWidth = Math.max(alternativeMaxWidth,                        matchWidthLocally ? margin : measuredWidth);            }            i += getChildrenSkipCount(child, i);        }        if (nonSkippedChildCount > 0 && hasDividerBeforeChildAt(count)) {            mTotalLength += mDividerHeight;        }        if (useLargestChild &&                (heightMode == MeasureSpec.AT_MOST || heightMode == 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 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)                        child.getLayoutParams();                // Account for negative margins                final int totalLength = mTotalLength;                mTotalLength = Math.max(totalLength, totalLength + largestChildHeight +                        lp.topMargin + lp.bottomMargin + getNextLocationOffset(child));            }        }        // Add in our padding        mTotalLength += mPaddingTop + mPaddingBottom;        int heightSize = mTotalLength;        // Check against our minimum height        heightSize = Math.max(heightSize, getSuggestedMinimumHeight());        // Reconcile our calculated size with the heightMeasureSpec        int heightSizeAndState = resolveSizeAndState(heightSize, heightMeasureSpec, 0);        heightSize = heightSizeAndState & 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 remainingExcess = heightSize - mTotalLength                + (mAllowInconsistentMeasurement ? 0 : consumedExcessSpace);        if (skippedMeasure || remainingExcess != 0 && totalWeight > 0.0f) {            float remainingWeightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;            mTotalLength = 0;            for (int i = 0; i < count; ++i) {                final View child = getVirtualChildAt(i);                if (child == null || child.getVisibility() == View.GONE) {                    continue;                }                final LayoutParams lp = (LayoutParams) child.getLayoutParams();                final float childWeight = lp.weight;                if (childWeight > 0) {                    final int share = (int) (childWeight * remainingExcess / remainingWeightSum);                    remainingExcess -= share;                    remainingWeightSum -= childWeight;                    final int childHeight;                    if (mUseLargestChild && heightMode != MeasureSpec.EXACTLY) {                        childHeight = largestChildHeight;                    } else if (lp.height == 0 && (!mAllowInconsistentMeasurement                            || heightMode == MeasureSpec.EXACTLY)) {                        // This child needs to be laid out from scratch using                        // only its share of excess space.                        childHeight = share;                    } else {                        // This child had some intrinsic height to which we                        // need to add its share of excess space.                        childHeight = child.getMeasuredHeight() + share;                    }                    final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(                            Math.max(0, childHeight), MeasureSpec.EXACTLY);                    final int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,                            mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin,                            lp.width);                    child.measure(childWidthMeasureSpec, childHeightMeasureSpec);                    // Child may now not fit in vertical dimension.                    childState = combineMeasuredStates(childState, child.getMeasuredState()                            & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT));                }                final int margin =  lp.leftMargin + lp.rightMargin;                final int measuredWidth = child.getMeasuredWidth() + margin;                maxWidth = Math.max(maxWidth, measuredWidth);                boolean matchWidthLocally = widthMode != MeasureSpec.EXACTLY &&                        lp.width == LayoutParams.MATCH_PARENT;                alternativeMaxWidth = Math.max(alternativeMaxWidth,                        matchWidthLocally ? margin : measuredWidth);                allFillParent = allFillParent && lp.width == LayoutParams.MATCH_PARENT;                final int totalLength = mTotalLength;                mTotalLength = Math.max(totalLength, totalLength + child.getMeasuredHeight() +                        lp.topMargin + lp.bottomMargin + getNextLocationOffset(child));            }            // Add in our padding            mTotalLength += mPaddingTop + mPaddingBottom;            // TODO: Should we recompute the heightSpec based on the new total length?        } else {            alternativeMaxWidth = Math.max(alternativeMaxWidth,                                           weightedMaxWidth);            // We have no limit, so make all weighted views as tall as the largest child.            // Children will have already been measured once.            if (useLargestChild && heightMode != MeasureSpec.EXACTLY) {                for (int i = 0; i < count; i++) {                    final View child = getVirtualChildAt(i);                    if (child == null || child.getVisibility() == View.GONE) {                        continue;                    }                    final LinearLayout.LayoutParams lp =                            (LinearLayout.LayoutParams) child.getLayoutParams();                    float childExtra = lp.weight;                    if (childExtra > 0) {                        child.measure(                                MeasureSpec.makeMeasureSpec(child.getMeasuredWidth(),                                        MeasureSpec.EXACTLY),                                MeasureSpec.makeMeasureSpec(largestChildHeight,                                        MeasureSpec.EXACTLY));                    }                }            }        }        if (!allFillParent && widthMode != MeasureSpec.EXACTLY) {            maxWidth = alternativeMaxWidth;        }        maxWidth += mPaddingLeft + mPaddingRight;        // Check against our minimum width        maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());        setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),                heightSizeAndState);        if (matchWidth) {            forceUniformWidth(count, heightMeasureSpec);        }    }    private void forceUniformWidth(int count, int heightMeasureSpec) {        // Pretend that the linear layout has an exact size.        int uniformMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(),                MeasureSpec.EXACTLY);        for (int i = 0; i< count; ++i) {           final View child = getVirtualChildAt(i);           if (child != null && child.getVisibility() != GONE) {               LinearLayout.LayoutParams lp = ((LinearLayout.LayoutParams)child.getLayoutParams());               if (lp.width == LayoutParams.MATCH_PARENT) {                   // Temporarily force children to reuse their old measured height                   // FIXME: this may not be right for something like wrapping text?                   int oldHeight = lp.height;                   lp.height = child.getMeasuredHeight();                   // Remeasue with new dimensions                   measureChildWithMargins(child, uniformMeasureSpec, 0, heightMeasureSpec, 0);                   lp.height = oldHeight;               }           }        }    }
  • AbsoluteLayout(绝对布局)
    可以放置多个控件,并且可以自己定义控件的x,y位置
  • RelativeLayout (相对布局)
    这个布局也是相对自由的布局,Android对该布局的child view的水平layout和垂直layout做了解析,由此我们可以FrameLayout的基础上使用标签或者java代码对垂直方向以及水平方向布局中views进行任意的控制。
    相关属性:

android:layout_centerInParent=”true|false”
android:layout_centerHorizontal=”true|false”
android:layout_alignParentRight=”true|false”

  • TableLayout(表格布局)
    将子元素的位置分配到行或者列中,一个TableLayout有许多的TableRow组成。

更多相关文章

  1. Android ImageView控件的setMaxWidth、setMaxHeight不起作用
  2. 如何在XML设定android控件的颜色(十六进制颜色码)
  3. 安卓控件属性
  4. Mono登录界面记住密码的控件
  5. Android Layout Tricks #2: Reusing layouts(Android 布局技巧2:重
  6. Android 点击父控件让子控件也可以响应点击事件
  7. 35、键盘布局的tableLayout备份
  8. 相对布局RelativeLayout
  9. android布局ui

随机推荐

  1. Android平台安全分析
  2. Android入门学习笔记(一):Android初认识
  3. android:padding和android:layout_margin
  4. Android安装的时候系统都做了些什么
  5. Android SDK Document 框架导读的翻译和
  6. android 获取versionName和versionCode以
  7. FFmpeg和android播放器
  8. Android应用程序键盘(Keyboard)消息处理机
  9. android 抓包
  10. ANDROID SHAPE鐢诲渾褰㈣儗鏅痏ANDROID瀹