02-实践-一个Android小布局引发的思考

你确定你对Android的布局精通了吗?如果你能立马用LinearLayout,RelativeLayout,ConstraintLayout说出如何让两个TextView左右水平居中该如何实现,那就不需要看下边的文章了,如果不能,还需要多多看官网实践,修炼自己。

接下来我们分别用LinearLayout,RelativeLayout,ConstraintLayout分别来实现让两个TextView居中显示。为了文章的简洁性,我用LL代替LinearLayout,用RL代替RelativeLayout,用CL代替ConstraintLayout。需求效果如下:

[图片上传失败...(image-6949d1-1692928645060)])


LL:

我们来看下LL属性代表的含义。

orientation :子View是以行还是以列展示的。如果是一行使用horizontal,一列则使用vertical。

gravity:控制LL包含的所有子View是如何排列的。这个值影响着单行或单列中所有子View水平或竖直的排列,还展示了一个对象应该如何在边界,x轴或y轴上放置它的内容。例如:最外层LL的gravity属性设置为center,那么它的子View就是在中间的。

layout_weight:设置单个子View在LL中是如何分配剩余空间的。官网默认权重为0。

layoutParams:影响LL中子View的位置和大小。


根据上边的属性含义我们来实现需求。首先在LL的最外层将gravity属性设置为center,让子View居中。然后再将TextView的weight属性设置为1,中间View的weight属性默认为0,分配剩余空间,最后将TextView的gravity属性设置为center让文字居中。效果实现。代码如下:


<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="[http://schemas.android.com/apk/res/android](http://schemas.android.com/apk/res/android)"

    xmlns:tools="[http://schemas.android.com/tools](http://schemas.android.com/tools)"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:gravity="center"

    android:orientation="horizontal"

    tools:context=".centerhorizontal.LLActivity">

    <TextView

        android:layout_width="50dp"

        android:layout_height="wrap_content"

        android:layout_weight="1"

        android:gravity="center"

        android:text="@string/left" />

    <View

        android:layout_width="2dp"

        android:layout_height="40dp"

        android:background="@color/colorPrimary" />

    <TextView

        android:layout_width="50dp"

        android:layout_height="wrap_content"

        android:layout_weight="1"

        android:gravity="center"

        android:text="@string/right" />

</LinearLayout>

LL的使用场景:如果是单层布局,最好使用LL,而不使用RL。因为RL绘制渲染速度慢,性能低。


RL:

定义:展示子View相对于父View或子View互相之间的位置。

好处:RL可以减少布局之间的嵌套。多层布局嵌套,用LL会增加布局层级,但是用RL一层即可,使应用更加扁平化。

使用场景:如果你发现自己使用了几个内部LL组,你可能想要去用一个RL去代替它。


我们来看看RL中CENTER_HORIZONTAL的属性含义:Rule that centers the child horizontally with respect to the bounds of its RelativeLayout parent。意思是规定子元素相对于父元素的边界水平居中。

根据上边的属性含义我们来实现需求。首先让View设置centerInParent属性为true,然后TextView宽度设置为match_parent,并设置centerVertical为true,根据相对位置分别放在View的左侧和右侧,最后设置gravity属性为center让文字居中,效果实现。代码如下:


<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="[http://schemas.android.com/apk/res/android](http://schemas.android.com/apk/res/android)"

    xmlns:tools="[http://schemas.android.com/tools](http://schemas.android.com/tools)"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    tools:context="com.example.ruru.android_constraintlayout.centerhorizontal.RLActivity">

    <View

        android:id="@+id/view"

        android:layout_width="3dp"

        android:layout_height="40dp"

        android:layout_centerInParent="true"

        android:background="@color/colorPrimary" />

    <TextView

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:layout_centerVertical="true"

        android:layout_toLeftOf="@id/view"

        android:gravity="center"

        android:text="@string/left" />

    <TextView

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:layout_centerVertical="true"

        android:layout_toRightOf="@id/view"

        android:gravity="center"

        android:text="@string/right" />

</RelativeLayout>


CL:

建议大家在看下边内容之前先结合ConstraintLayout官网认真实践下这个链接的文章。

ConstraintLayout,多层级布局嵌套的解药!

https://juejin.im/entry/5a53676bf265da3e3d48feba

这篇文章讲的非常棒,将ConstraintLayout常见的用法都囊括了进来。


定义:允许你去灵活的定义和更改布局。

以下几个属性含义是我根据官网得出的,剩下自己需要自行查看官网:

relative position:相对位置。允许你去定义一个相对于另一个的布局。可以在水平和竖直方向约束布局。例如:buttonB在buttonA的右边:buttonB设置属性app:layout_constraintLeft_toRightOf。意思是告诉系统我们想要buttonB的左边界被约束到buttonA的右边。

margin:边缘空白。margin可以是确定的值或者等于0或者持有一个尺寸。

bias:偏斜。两个不可能的约束最后居中或按偏斜排列。

guideline:辅助线。约束布局对不可见的View有控制权。


优势:

布局调整更为方便,可以直接拖拽进行操作;

布局之间相对位置更好控制,CL的guideline属性对不可见的View具有控制权,View设置为GONE不影响界面效果;

动态创建布局方便,对控件的控制能力更加强大,可以实现动画效果;

CL的chains属性有三种模式,比weight属性更加强大,在权重分配比LL还多一个bias属性;

减少页面布局层级,使页面更加扁平化,渲染速度更快,性能更高。


根据上边的属性含义我们来实现需求。

第一种:用偏斜bias来实现需求,等价于LL的weight属性。TextView设置水平方向bias分别为0.25和0.75,竖直方向bias默认为0.5。View水平和竖直都默认为0.5。代码如下:


<?xml version="1.0" encoding="utf-8"?>

<android.support.constraint.ConstraintLayout xmlns:android="[http://schemas.android.com/apk/res/android](http://schemas.android.com/apk/res/android)"

    xmlns:app="[http://schemas.android.com/apk/res-auto](http://schemas.android.com/apk/res-auto)"

    xmlns:tools="[http://schemas.android.com/tools](http://schemas.android.com/tools)"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    tools:context=".centerhorizontal.CL1Activity">

    <TextView

        android:id="@+id/tv_left"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="@string/left"

        app:layout_constraintBottom_toBottomOf="parent"

        app:layout_constraintHorizontal_bias="0.25"

        app:layout_constraintLeft_toLeftOf="parent"

        app:layout_constraintRight_toRightOf="parent"

        app:layout_constraintTop_toTopOf="parent" />

    <View

        android:layout_width="3dp"

        android:layout_height="40dp"

        android:background="@color/colorPrimary"

        app:layout_constraintBottom_toBottomOf="parent"

        app:layout_constraintLeft_toRightOf="@id/tv_left"

        app:layout_constraintRight_toLeftOf="@id/tv_right"

        app:layout_constraintTop_toTopOf="parent" />

    <TextView

        android:id="@+id/tv_right"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="@string/right"

        app:layout_constraintBottom_toBottomOf="parent"

        app:layout_constraintHorizontal_bias="0.75"

        app:layout_constraintLeft_toLeftOf="parent"

        app:layout_constraintRight_toRightOf="parent"

        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

第二种:用链条chains来实现需求。chains为水平或竖直方向控件之间形成约束关系,即形成链条。chains有三种模式,本例用spread平分空间即可,让TextView的weight属性设置为1,最后用gravity让TextView的文字居中。代码如下:


<?xml version="1.0" encoding="utf-8"?>

<android.support.constraint.ConstraintLayout xmlns:android="[http://schemas.android.com/apk/res/android](http://schemas.android.com/apk/res/android)"

    xmlns:app="[http://schemas.android.com/apk/res-auto](http://schemas.android.com/apk/res-auto)"

    xmlns:tools="[http://schemas.android.com/tools](http://schemas.android.com/tools)"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    tools:context=".centerhorizontal.CL2Activity">

    <TextView

        android:id="@+id/tvLeft"

        android:layout_width="0dp"

        android:layout_height="wrap_content"

        android:gravity="center"

        android:text="@string/left"

        app:layout_constraintBottom_toBottomOf="parent"

        app:layout_constraintHorizontal_chainStyle="spread"

        app:layout_constraintHorizontal_weight="1"

        app:layout_constraintLeft_toLeftOf="parent"

        app:layout_constraintRight_toLeftOf="@id/view"

        app:layout_constraintTop_toTopOf="parent" />

    <View

        android:id="@+id/view"

        android:layout_width="3dp"

        android:layout_height="40dp"

        android:background="@color/colorPrimary"

        app:layout_constraintBottom_toBottomOf="parent"

        app:layout_constraintLeft_toRightOf="@id/tvLeft"

        app:layout_constraintRight_toLeftOf="@id/tvRight"

        app:layout_constraintTop_toTopOf="parent" />

    <TextView

        android:id="@+id/tvRight"

        android:layout_width="0dp"

        android:layout_height="wrap_content"

        android:gravity="center"

        android:text="@string/right"

        app:layout_constraintBottom_toBottomOf="parent"

        app:layout_constraintHorizontal_weight="1"

        app:layout_constraintLeft_toRightOf="@id/view"

        app:layout_constraintRight_toRightOf="parent"

        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

第三种:用辅助线guideline实现需求。先设置一条水平方向的辅助线,让它距离上边界为整个界面的一半,设置layout_constraintGuide_percent为50%,然后设置两个TextView和View三者之间左,上,右,下之间的约束关系。有点类似于RL中的center类属性。代码如下:


<?xml version="1.0" encoding="utf-8"?>

<android.support.constraint.ConstraintLayout xmlns:android="[http://schemas.android.com/apk/res/android](http://schemas.android.com/apk/res/android)"

    xmlns:app="[http://schemas.android.com/apk/res-auto](http://schemas.android.com/apk/res-auto)"

    xmlns:tools="[http://schemas.android.com/tools](http://schemas.android.com/tools)"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    tools:context=".centerhorizontal.CL3Activity">

    <android.support.constraint.Guideline

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:orientation="horizontal"

        app:layout_constraintGuide_percent="0.5" />

    <TextView

        android:id="@+id/tvLeft"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="@string/left"

        app:layout_constraintBottom_toBottomOf="parent"

        app:layout_constraintLeft_toLeftOf="parent"

        app:layout_constraintRight_toLeftOf="@id/view"

        app:layout_constraintTop_toTopOf="parent" />

    <View

        android:id="@+id/view"

        android:layout_width="3dp"

        android:layout_height="40dp"

        android:background="@color/colorPrimary"

        app:layout_constraintBottom_toBottomOf="parent"

        app:layout_constraintLeft_toRightOf="@id/tvLeft"

        app:layout_constraintRight_toLeftOf="@id/tvRight"

        app:layout_constraintTop_toTopOf="parent" />

    <TextView

        android:id="@+id/tvRight"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="@string/right"

        app:layout_constraintBottom_toBottomOf="parent"

        app:layout_constraintLeft_toRightOf="@id/view"

        app:layout_constraintRight_toRightOf="parent"

        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>


划重点:

权重分配:

LL:gravity+weight(场景:分配剩余空间)

RL:相对位置gravity+center属性(场景:控件之间相互约束)

CL:偏斜bias(场景:按比例确定具体位置,等价于LL中的weight)

CL:链条chain,chainStyle+weight+gravity(场景:水平或竖直方向控件之间形成约束关系,即形成链条)

CL:辅助线guideline(场景:作为参照物进行对齐,控件之间形成约束,有点类似于RL中的center类属性)

综上来看,本例最适合采用的方法其实是偏斜bias,接下来是链条chain,因为它们都可以分配权重。


划重点:

三大布局对比:

单层布局:用LL,因为用RL绘制渲染速度慢,性能低。

多层嵌套布局:用RL,因为用LL会增加页面嵌套布局层级。

CL的优点:减少页面布局层级,使页面更加扁平化,渲染速度更快,提升性能,比LL和RL更加强大。


附项目地址:

Github传送门:https://github.com/2211785113/Android_ConstraintLayout


快问快答小测试:

1.举一反三:根据上方的例子做出下列两种效果的界面。

[图片上传失败...(image-1b362a-1692928645060)])

提示:最里层TextView和ImageView不管用RL和LL都需要再加一层LL。

需求:如果整体布局左右距边界加间隔,最外层布局设置padding即可。

[图片上传失败...(image-1f791e-1692928645060)])

水平竖直方向切换:擅用orientation属性。

2.用ConstraintLayout实现SwipeRefreshLayout里包含TabLayout和ViewPager的界面。

实现:

我的第13期开源项目里将包含这个布局。

布局位于项目 res/layout/activity_srl_vp_old.xml,res/layout/activity_srl_vp.xml

github传送门:

https://github.com/2211785113/Android_SlidingConflictDemo

注意:

activity_srl_vp_old.xml:使用了chain+packed模式,效果无法实现,刷新控件不显示。

原因:根据源码,SRL不包含子View就无法onMeasure,刷新控件就不会显示。看源码。

activity_srl_vp.xml:SRL里包含一个RelativeLayout布局,刷新控件即可显示。


涨姿势:

需求:LL让子View居中除了最外层LL设置gravity属性为center还有什么办法?

提示:也可以让子View设置layout_gravity属性。

特别提示:

父View方向为vertical时,子View的layout_gravity属性设置为left/right/center_horizontal等横向属性才会生效。

父View方向为horizontal时,子View的layout_gravity属性设置为top/bottom/center_vertical等纵向属性才会生效。

子View的layout_gravity属性设置为center,只有一个方向会生效。水平居中设置center起作用。垂直居中设置center起作用。


小贴士:

gravity和layout_gravity的区别:

gravity:用于父组件。表示父组件的子组件在组件中的位置。

layout_gravity:用于子组件。表示子组件自身在父组件中的位置。


margin和padding的区别:

margin:指定此视图左、上、右和底部的额外空间。

padding:以这个视图的左、上、右、下部分的像素显示,以特定的像素偏移视图的内容。比如:left padding为2将使View的内容从左边缘向右移动2个像素。

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

推荐阅读更多精彩内容