二之番外.Android六种布局详细讲解

这篇就对LinearLayout、RelativeLayout、自定义ViewGroup、FrameLayout、TableLayout、AbsoluteLayout六种布局进行详细的讲解。

1.LinearLayout布局

线性布局,两种排法:

  • 从左到右
    android:orientation="horizontal"
  • 从上到下
    android:orientation="vertical"
    具体上图
LinearLayout

一个竖向的大LinearLayout嵌套着两个小LinearLayout,第一个小LinearLayout为横向,第二个小LinearLayout为竖向。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"    
    android:layout_width="match_parent"    
    android:layout_height="match_parent"    
    android:orientation="vertical">    
<LinearLayout        
    android:layout_width="match_parent"        
    android:layout_height="250dp"        
    android:orientation="horizontal">        
    <TextView           
        android:layout_width="96dp"      
        android:layout_height="match_parent" 
        android:background="#b2dfdb" />        
    <TextView            
        android:layout_width="96dp"               
        android:layout_height="match_parent"             
        android:background="#80cbc4" />       
     <TextView            
        android:layout_width="96dp"                   
        android:layout_height="match_parent"            
        android:background="#4db6ac" />        
    <TextView            
        android:layout_width="96dp"            
        android:layout_height="match_parent"            
        android:background="#26a69a" />    
</LinearLayout>    
<LinearLayout        
    android:layout_width="match_parent"            
    android:layout_height="match_parent"        
    android:orientation="vertical">        
    <TextView           
        android:layout_width="match_parent"            
        android:layout_height="68dp"            
        android:background="#b2dfdb" />        
    <TextView            
        android:layout_width="match_parent"                
        android:layout_height="68dp"            
        android:background="#80cbc4" />        
    <TextView            
        android:layout_width="match_parent"                
        android:layout_height="68dp"            
        android:background="#4db6ac" />        
    <TextView            
        android:layout_width="match_parent"                    
        android:layout_height="68dp"            
        android:background="#26a69a" />    
</LinearLayout>
</LinearLayout>

2.RelativeLayout布局

参考其他控件进行布局,默认为父控件。
有三种类型的属性:

  • 属性值是true或false
    • android:layout_centerHrizontal 水平居中
    • android:layout_centerVertical 垂直居中
    • android:layout_centerInparent 相对于父元素完全居中。
    • android:layout_alignParentBottom 位于父元素的下边缘
    • android:layout_alignParentTop 位于父元素的上边缘
    • android:layout_alignParentLeft 位于父元素的左边缘
    • android:layout_alignParentRight 位于父元素的右边缘
  • 属性值是"@id/*“
    • android:layout_below 在某元素的下方
    • android:layout_above 在某元素的上方
    • andorid:layout_toRightOf 在某元素的右方
    • android:layout_toLeftOf 在某元素的左方
    • android:layout_alignBottom 和某元素下方对齐
    • android:layout_alignTop 和某元素上方对齐
    • android:layout_alignRight 和某元素右方对齐
    • android:layout_alignLeft 和某元素左方对齐
  • 属性值是数值
    • android:layout_marginLeft 离某元素左边缘的距离
    • android:layout_marginRight 离某元素右边缘的距离
    • android:layout_marginTop 离某元素上边缘的距离
    • android:layout_marginBottom 离某元素下边缘的距离

各取一个来写例子,如图。

RelativeLayout

注意

  • 如果没有定义左右,那么默认在左边,如果没有定义上下,默认在上边。
  • 相同位置,新定义的元素会覆盖旧的元素。例:1被2覆盖了。
  • 4只定义了在父元素的下部,左右没有定义,于是默认就在左边了。
  • android:layout_below,在某元素的下部并不意味着就一定是紧随某元素,只是在下部的默认位置。例如:5是在3的下部,但是是在下部的默认左边。
  • 6为下边缘对齐3,7为marginLeft=150dp。
  • 8为多个属性共同定义的结果。首先是在3的右部,然后是垂直居中,然后marginLeft=100dp得到最后位置。

代码如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        style="@style/btn_relative"

        android:text="1" />

    <TextView
        style="@style/btn_relative"

        android:text="2" />

    <TextView
        android:id="@+id/txt_center"
        style="@style/btn_relative"

        android:layout_centerInParent="true"

        android:text="3" />

    <TextView
        style="@style/btn_relative"

        android:layout_alignParentBottom="true"

        android:text="4" />

    <TextView
        style="@style/btn_relative"

        android:layout_below="@id/txt_center"
        android:background="#d0d9ff"

        android:text="5" />

    <TextView
        style="@style/btn_relative"

        android:layout_alignBottom="@+id/txt_center"

        android:text="6" />

    <TextView
        style="@style/btn_relative"

        android:layout_marginLeft="150dp"

        android:text="7" />

    <TextView
        style="@style/btn_relative"

        android:layout_centerVertical="true"
        android:layout_marginLeft="100dp"
        android:layout_toRightOf="@id/txt_center"

        android:text="8" />
</RelativeLayout>

3.MyLayout布局(自定义ViewGroup)

自定义布局主要是重写两个方法:

  • onMeasure() 这个是写自定义容器的大小。
  • onLayout() 这个是写子元素的布局。
    我自己写了一个自定义布局,是顺序填充会延对角线进行排列。

3.1onMeasure()

 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        /**
         * 获得此ViewGroup上级容器为其推荐的宽和高,以及计算模式
         */
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
        int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);

        // 计算出所有的childView的宽和高
        measureChildren(widthMeasureSpec, heightMeasureSpec);
        /**
         * width和height是当wrap_content时使用的属性。
         */
        int width = 0;
        int height = 0;
        int cCount = getChildCount();
        int cWidth = 0;
        int cHeight = 0;
        /**
         * 在这里计算当wrap_content时,布局的大小。
         */
        for (int i = 0; i < cCount; i++) {
            View childView = getChildAt(i);
            cWidth = childView.getMeasuredWidth();
            cHeight = childView.getMeasuredHeight();
            width += cWidth;
            height += cHeight;
        }
        /**
         * 如果是wrap_content设置为我们计算的值
         * 否则:直接设置为父容器计算的值
         */
        setMeasuredDimension((widthMode == MeasureSpec.EXACTLY) ? sizeWidth
                : width, (heightMode == MeasureSpec.EXACTLY) ? sizeHeight
                : height);

    }

首先要说一下布局计算模式,即最后的EXACTLY。一共有三种计算模式:

  • MeasureSpec.EXACTLY:精确尺寸,相当于具体数值和match_parent。
  • MeasureSpec.AT_MOST:最大尺寸,相当于 warp_content。
  • MeasureSpec.UNSPECIFIED:未指定尺寸,这种情况不多,一般用于AdapterView。

最后的设定大小时,如果是精确尺寸就是用sizeWidth即获取的尺寸,如果是最大尺寸就是要我们自己计算的那个尺寸了。
onMeasure()最主要的功能就是计算wrap_content的尺寸设置尺寸
我将这个方法称为“建画布”,先建了画布才能在上面绘图嘛。

3.2 onLayout()

@Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int cCount = getChildCount();

        /**
         * 遍历所有childView根据其宽和高,以及margin进行布局
         */
        for (int i = 0; i < cCount; i++) {
            View childView = getChildAt(i);
            r = l + childView.getMeasuredWidth();
            b = t + childView.getMeasuredHeight();
            childView.layout(l, t, r, b);
            l += childView.getMeasuredWidth();
            t += childView.getMeasuredHeight();
        }
    }

这个方法的作用是设置摆放子元素的位置。其中onLayout()传入的l、t、r、b分别是这样


  • l,t分别对应子元素左上角的left,top坐标
  • r,b分别对应子元素右下角的right,bottom坐标

并且可以使用childview.getMeasuredWidth()和childView.getMeasureHeight()得到子元素的宽和高。
这样就可以来对每个子元素进行布局了。
我称这个方法为“定位置”。定完位置后那么子元素就被放到了我们想要的地方。
这样一个自定义ViewGroup就可以使用了。
xml文件如下:

<?xml version="1.0" encoding="utf-8"?>
<com.example.layoutdemo.MyLayout.MyLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    >

        <TextView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:background="#b2dfdb" />

        <TextView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:background="#80cbc4" />

        <TextView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:background="#4db6ac" />

        <TextView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:background="#26a69a" />

</com.example.layoutdemo.MyLayout.MyLayout>

最后效果如图:


MyLayout

4.FrameLayout布局

帧布局,这个布局的特点是从左上角开始,后面的会覆盖前面的控件。
代码如下:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="100dp"
        android:textColor="#9c27b0"
        android:text="第一层"/>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="80dp"
        android:textColor="#e91e63"
        android:text="第二层"/>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="60dp"
        android:textColor="#e51c23"
        android:text="第三层"/>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="40dp"
        android:textColor="#5677fc"
        android:text="第四层"/>
</FrameLayout>

实际效果如下:


FrameLayout

5.TableLayout布局

表格布局。
它遵循着以下结构:

<TableLayout>
    <TableRow>
    <!-在这里填充第一行的元素->
    </TableRow>
    <TableRow>
    <!-在这里填充第二行的元素->
    </TableRow>    
</TableLayout>

还有几个重要属性:

  • 写在TableLayout中的属性
    • android:stretchColumns 设置第几列为伸展(0表示第一列)
    • android:shrinkColumns 设置第几列为收缩
    • android:collapseColumns 设置第几列为隐藏
  • 写在TableRow里的控件里的属性
    • android:layout_column 设置控件在第几列
    • android:layout_span 设置控件能跨多少列

代码如下:

<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:collapseColumns="2"
    android:shrinkColumns="1"
    android:stretchColumns="0">

    <TableRow
       >
        <TextView android:text="我是伸展的第一列" />

        <TextView android:text="我是收缩的第二列" />

        <TextView android:text="我被隐藏了" />
    </TableRow>

    <TableRow>
        <TextView android:text="我可以伸展的很长很长很长长" />

        <TextView android:text="我可以收缩,我可以变的很深很深很深" />

        <TextView android:text="我被隐藏了T_T" />
    </TableRow>

    <TableRow>
        <TextView
            android:layout_column="1"
            android:text="我要在第2列" />
    </TableRow>

    <TableRow>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_column="0"
            android:layout_span="2"
            android:text="我要               跨                  两                列" />
    </TableRow>
</TableLayout>

最后效果如下:


TableLayout

6.AbsoluteLayout布局

绝对布局,极力不推荐,官方已经舍弃。
定义两个控件左上角坐标轴
android:layout_xandroid:layout_y来控制位置。

<?xml version="1.0" encoding="utf-8"?>
<AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        style="@style/btn_relative"

        android:text="1" />

    <TextView
        style="@style/btn_relative"
        android:layout_x="60dp"
        android:layout_y="60dp"
        android:text="1" />

    <TextView
        style="@style/btn_relative"
        android:layout_x="160dp"
        android:layout_y="160dp"
        android:text="1" />

    <TextView
        style="@style/btn_relative"
        android:layout_x="260dp"
        android:layout_y="260dp"
        android:text="1" />
</AbsoluteLayout>

最后效果如下:


AbsoluteLayout

源码下载地址:LayoutDemo

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,204评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,091评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,548评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,657评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,689评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,554评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,302评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,216评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,661评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,851评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,977评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,697评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,306评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,898评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,019评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,138评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,927评论 2 355

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,138评论 25 707
  • 欢迎Follow我的GitHub, 关注我的CSDN. 其余参考Android目录. 转载请注明出处:http:/...
    passiontim阅读 4,764评论 0 31
  • Android功能强大,界面华丽,但是众多的布局属性就害苦了开发者,下面这篇文章结合了网上不少资料.第一类:属性值...
    HangChen阅读 4,873评论 0 24
  • 今天是农历八月十六,中秋节后第一天,也是观潮时节。 起床,洗漱,早餐,地铁之后,我赶到客运中心,时间刚刚过八点一点...
    听风牧语阅读 553评论 0 2
  • 之前有说 就像云彩一样 抓不住 远远的看着 静静地欣赏 不远不近 欣赏你的知性 你的独特 你的喜怒哀乐 愿你今后的...
    木目先森阅读 239评论 0 0