Android RelativeLayout和LinearLayout
来源:互联网 发布:指南针炒股软件卸载 编辑:程序博客网 时间:2024/05/21 07:50
我们知道Android中页面布局有以下五种:
五大布局简介
- LinearLayout 线性布局
线性布局是按照水平或垂直的顺序将子元素(可以是控件或布局)依次按照顺序排列,每一个元素都位于前面一个元素之后。线性布局分为两种:水平方向和垂直方向的布局。分别通过属性android:orientation="vertical" 和 android:orientation="horizontal"来设置。android:layout_weight 表示子元素占据的空间大小的比例,有人说这个值大小和占据空间成正比,有人说反比。(稍后会研究一下)
- RelativeLayout 相对布局
RelativeLayout继承于android.widget.ViewGroup,其按照子元素之间的位置关系完成布局的,作为Android系统五大布局中最灵活也是最常用的一种布局方式,非常适合于一些比较复杂的界面设计。
注意:在引用其他子元素之前,引用的ID必须已经存在,否则将出现异常。
- TableLayout 表格布局
表格布局,适用于多行多列的布局格式,每个TableLayout是由多个TableRow组成,一个TableRow就表示TableLayout中的每一行,这一行可以由多个子元素组成。实际上TableLayout和TableRow都是LineLayout线性布局的子类。但是TableRow的参数android:orientation属性值固定为horizontal,且android:layout_width=MATCH_PARENT android:layout_height=WRAP_CONTENT。所以TableRow实际是一个横向的线性布局,且所以子元素宽度和高度一致。
注意:在TableLayout中,单元格可以为空,但是不能跨列,意思是只能不能有相邻的单元格为空。
在TableLayout布局中,一列的宽度由该列中最宽的那个单元格指定,而该表格的宽度由父容器指定。可以为每一列设置以下属性:
Shrinkable 表示该列的宽度可以进行收缩,以使表格能够适应父容器的大小
Stretchable 表示该列的宽度可以进行拉伸,以使能够填满表格中的空闲空间
Collapsed 表示该列会被隐藏
TableLayout中的特有属性:
android:collapseColumns
android:shrinkColumns
android:stretchColumns = "0,1,2,3"
- AbsoluteLayou 绝对布局
- FrameLayout 框架布局
两者相似之处:
控件宽度
android:layout_width="80px"
android:layout_width =“wrap_content”
android:layout_width =“match_parent”
控件高度
android:layout_height="80px"
android:layout_height =“wrap_content”
android:layout_height =“match_parent”
控件排布
android:orientation="horizontal”
android:orientation="vertical“
控件间距
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:layout_marginTop="5dip"
android:layout_marginRight="5dip"
android:paddingLeft="5dip"
控件显示位置
android:gravity="center"
android:gravity="center_horizontal"
android:layout_gravity是本元素对父元素的重力方向。
android:layout_gravity属性则设置控件本身相对于父控件的显示位置
android:gravity是本元素所有子元素的重力方向。
android:layout_gravity="center_vertical"
android:layout_gravity="left"
android:layout_gravity="left|bottom"
TextView中文本字体
android:text="@String/text1"
android:textSize="20sp"
android:textColor=”#ff123456”
android:textStyle="bold"
TextView中,控制其以...结束
android:ellipsize="end"
只有一行
android:singleLine="true"
定义控件是否可见
android:visibility=”visible”
android:visibility=”invisible” //不可见,但是在布局中占用的位置还在
android:visibility=”gone” //不可见,完全从布局中消失
定义背景图片
android:background="@drawable/img_bg"
seekbar控件背景图片及最大值
android:progressDrawable="@drawable/seekbar_img"
android:thumb="@drawable/thumb"
android:max = "60"
android:layout_alignWithParentIfMissing
不同之处
在父亲布局的相对位置
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true "
在某个控件的相对位置
android:layout_toRightOf="@id/button1"
android:layout_toLeftOf="@id/button1"
android:layout_below="@id/button1 "
android:layout_above=“@id/button1”
定义和某控件对奇
android:layout_alignTop=”@id/button1”
android:layout_alignBottom=”@id/button1”
android:layout_alignLeft=”@id/button1”
android:layout_alignRight=”@id/button1”
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_centerInParent="true"
仅在LinearLayout中有效
设置控件在一排或一列中所占比例值
android:layout_weight="1"
性能分析
RelativeLayout
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {......View[] views = mSortedHorizontalChildren;int count = views.length;for (int i = 0; i < count; i++) { View child = views[i]; if (child.getVisibility() != GONE) { LayoutParams params = (LayoutParams) child.getLayoutParams(); int[] rules = params.getRules(layoutDirection); applyHorizontalSizeRules(params, myWidth, rules); measureChildHorizontal(child, params, myWidth, myHeight); if (positionChildHorizontal(child, params, myWidth, isWrapContentWidth)) { offsetHorizontalAxis = true; } }}views = mSortedVerticalChildren;count = views.length;final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;for (int i = 0; i < count; i++) { View child = views[i]; if (child.getVisibility() != GONE) { LayoutParams params = (LayoutParams) child.getLayoutParams(); applyVerticalSizeRules(params, myHeight); measureChild(child, params, myWidth, myHeight); if (positionChildVertical(child, params, myHeight, isWrapContentHeight)) { offsetVerticalAxis = true; } if (isWrapContentWidth) { if (isLayoutRtl()) { if (targetSdkVersion < Build.VERSION_CODES.KITKAT) { width = Math.max(width, myWidth - params.mLeft); } else { width = Math.max(width, myWidth - params.mLeft - params.leftMargin); } } else { if (targetSdkVersion < Build.VERSION_CODES.KITKAT) { width = Math.max(width, params.mRight); } else { width = Math.max(width, params.mRight + params.rightMargin); } } } if (isWrapContentHeight) { if (targetSdkVersion < Build.VERSION_CODES.KITKAT) { height = Math.max(height, params.mBottom); } else { height = Math.max(height, params.mBottom + params.bottomMargin); } } if (child != ignore || verticalGravity) { left = Math.min(left, params.mLeft - params.leftMargin); top = Math.min(top, params.mTop - params.topMargin); } if (child != ignore || horizontalGravity) { right = Math.max(right, params.mRight + params.rightMargin); bottom = Math.max(bottom, params.mBottom + params.bottomMargin); } }}......}
根据上述关键代码,RelativeLayout分别对所有子View进行两次measure,横向纵向分别进行一次。
LinearLayout
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (mOrientation == VERTICAL) { measureVertical(widthMeasureSpec, heightMeasureSpec); } else { measureHorizontal(widthMeasureSpec, heightMeasureSpec); }}
void measureVertical(int widthMeasureSpec, int heightMeasureSpec) {......for (int i = 0; i < count; ++i) { ...... LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams(); totalWeight += lp.weight; if (heightMode == MeasureSpec.EXACTLY && lp.height == 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. final int totalLength = mTotalLength; mTotalLength = Math.max(totalLength, totalLength + lp.topMargin + lp.bottomMargin); skippedMeasure = true; } else { int oldHeight = Integer.MIN_VALUE; if (lp.height == 0 && lp.weight > 0) { // heightMode 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 height of 0 oldHeight = 0; 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). measureChildBeforeLayout( child, i, widthMeasureSpec, 0, heightMeasureSpec, totalWeight == 0 ? mTotalLength : 0); if (oldHeight != Integer.MIN_VALUE) { lp.height = oldHeight; } final int childHeight = child.getMeasuredHeight(); final int totalLength = mTotalLength; mTotalLength = Math.max(totalLength, totalLength + childHeight + lp.topMargin + lp.bottomMargin + getNextLocationOffset(child)); if (useLargestChild) { largestChildHeight = Math.max(childHeight, largestChildHeight); } } ......
LinearLayout首先会对所有的子View进行measure,并计算totalWeight(所有子View的weight属性之和),然后判断子View的weight属性是否为最大,如为最大则将剩余的空间分配给它。如果不使用weight属性进行布局,则不进行第二次measure。
<span style="font-family:SimSun;font-size:12px;">// 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 = heightSize - mTotalLength;if (skippedMeasure || delta != 0 && totalWeight > 0.0f) { float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight; mTotalLength = 0; for (int i = 0; i < count; ++i) { final View child = getVirtualChildAt(i); if (child.getVisibility() == View.GONE) { continue; } LinearLayout.LayoutParams lp = (LinearLayout.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 childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin, lp.width); // TODO: Use a field like lp.isMeasured to figure out if this // child has been previously measured if ((lp.height != 0) || (heightMode != MeasureSpec.EXACTLY)) { // child was measured once already above... // base new measurement on stored values int childHeight = child.getMeasuredHeight() + share; if (childHeight < 0) { childHeight = 0; } child.measure(childWidthMeasureSpec, MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY)); } else { // child was skipped in the loop above. // Measure for this first time here child.measure(childWidthMeasureSpec, MeasureSpec.makeMeasureSpec(share > 0 ? share : 0, MeasureSpec.EXACTLY)); } // Child may now not fit in vertical dimension. childState = combineMeasuredStates(childState, child.getMeasuredState() & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT)); } ...... } ......} 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)); } } }}......}</span>结论:RelativeLayout将对所有的子View进行两次measure,而LinearLayout在使用weight属性进行布局时也会对子View进行两次measure,如果他们位于整个View树的顶端时并可能进行多层的嵌套时,位于底层的View将会进行大量的measure操作,大大降低程序性能。因此,应尽量将RelativeLayout和LinearLayout置于View树的底层,并减少嵌套。
文章参考:http://www.tuicool.com/articles/uQ3MBnj
- 【Android】 LinearLayout和RelativeLayout
- Android LinearLayout和RelativeLayout
- Android RelativeLayout和LinearLayout
- android布局 LinearLayout和RelativeLayout
- android LinearLayout和RelativeLayout实现精确布局
- android LinearLayout和RelativeLayout实现精确布局
- android LinearLayout和RelativeLayout实现精确布局
- Android学习 - LinearLayout布局和RelativeLayout布局
- android LinearLayout和RelativeLayout实现精确布局
- android 入门 一 LinearLayout和RelativeLayout
- android LinearLayout和RelativeLayout实现精确布局
- Android中LinearLayout和RelativeLayout使用详解
- android LinearLayout和RelativeLayout实现精确布局
- android入门-LinearLayout和RelativeLayout 属性对比
- android linearLayout 和 RelativeLayout使用的注意事项
- Android LinearLayout和RelativeLayout 布局1
- Android LinearLayout和RelativeLayout 布局2
- Android 布局之LinearLayout和RelativeLayout
- asp.net IsPostBack深入探讨
- Linux设备驱动模型二 kobject
- 汉字转化为拼音
- easyui datagrid 跳转指定页面问题
- TCP协议中的三次握手和四次挥手(图解)
- Android RelativeLayout和LinearLayout
- iOS--NSDictionary字典的初始化增删
- 动态加载dll(比如webapi)
- 问与答——怎样解决终极问题带来的虚无感
- 从1到n整数中1出现的次数
- 使用monkeyrunner实现手机自动转账功能
- Linux设备驱动模型三 kset
- 翻译 Cg Program in Unity - A.2 Vertex Transformations (1)
- 调试 Credential Provider 的简单方法