Hacks布局篇-Hack1 使用weight属性实现控件的居中
作者:李旺成
时间:2016年5月6日
想要的效果
想要的效果如上图所示,要实现这样一个效果:按钮居中显示,并且占据父控件宽度的一半。
看上去好像挺简单的,可以有很多实现方案,那最佳方案或者说最简单的方案是不是大家都会呢?
这里给出两个方案,具体选哪个看自己的实际情况。
方案一:weightSum 和 layout_weight 配合
先看效果:
居中显示宽度为父控件一半(一)实现代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:weightSum="2"
tools:context="com.diygreen.androidhackslayout.Hack1Activity">
<Button
android:id="@+id/btn_center"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="居中按钮" />
</LinearLayout>
原理分析
这里涉及到 LinearLayout 的 weightSum 属性与子控件的 layout_weight 属性配合使用。考虑到大家对 layout_weight 应该更了解,这里先讨论下 layout_weight。
layout_weight 属性
首先,看一下 layout_weight 属性的作用:
它是用来分配剩余空间的一个属性,可以设置它的权重。
然后,理解 layout_weight 的“真实含义”
这个属性大家一般都用过,但是可能都不是很清楚具体是怎么回事(反正我以前是这样,看着显示效果调,效果出来就万事大吉,没有考虑过为什么),这里稍微介绍下 layout_weight 的“真实含义”。
android:layout_weight 的真实含义是:一旦 View 设置了该属性(假设有效的情况下),那么该 View 的宽度等于原有宽度(android:layout_width)加上剩余空间的占比!
设屏幕宽度为 L,在两个 View 的宽度都为 match_parent 的情况下,原有宽度为 L,两个的 View 的宽度都为 L,那么剩余宽度为 L-(L+L) = -L, 左边的 View 占比三分之一,所以总宽度是 L+(-L)*1/3 = (2/3)L。事实上默认的 View 的 weight 这个值为0,一旦设置了这个值,那么所在 View 在绘制的时候执行 onMeasure 两次的原因就在这。
Google 官方推荐,当使用 weight 属性时,将 width 设为 0dp 即可,效果跟设成 wrap_content 是一样的。这样 weight 就可以理解为占比了!(参考:android:layout_weight的真实含义)
最后,稍微总结一下
在 layout_width 设置为 much_parent 的時候,layout_weight 所代表的是你的控件要优先尽可能的大,但这个大是有限度的,即 much_parent;
在 layout_width 设置为 wrap_content 的时候(这和设置为 0dp 一致),layout_weight 所代表的是你的控件要优先尽可能的小,但这个小是有限度的,即 wrap_content。(参考自:Android中 android:layout_weight 属性 完美解释)
weightSum 属性
LinearLayout 的 weightSum 属性,我基本上是第一次使用(就是在这个示例中),老规矩先看看官方的介绍:
weightSum 属性简单解释一下:
“定义 weight 总和的最大值。如果未指定该值,以所有子控件的 layout_weight 属性的累加值作为总和的最大值。一个典型的案例是:通过指定子控件的 layout_weight 属性为 0.5,并设置 LinearLayout 的 weightSum 属性为 1.0,实现子控件占据可用宽度的 50%”。(参考自:《50 Android Hacks》)
源码分析
源码分析在上面的代码中, LinearLayout 的 android:weightSum 属性值设置为 "2",表示其内部所有子控件的 weight 比例总和是 2。示例中 LinearLayout 中只有一个子控件:Button。该 Button 的 android:layout_width 设置为 "0dp",因此需要根据 android:weightSum 来决定 Button 的 width。Button 的 android:layout_weight 设置为 "1",即 android:weightSum 属性值的一半,所以,Button 将占据 50% 的可用空间。
方案二:PercentXxxLayout
先看效果:
居中显示宽度为父控件一半(二)实现代码
<?xml version="1.0" encoding="utf-8"?>
<android.support.percent.PercentFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.diygreen.androidhackslayout.Hack1Activity">
<Button
android:id="@+id/btn_center"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:layout_widthPercent="50%"
android:text="居中按钮(二)" />
</android.support.percent.PercentFrameLayout>
原理分析
百分比布局,做过前端的同学应该知道网页提供百分比计算大小,Web 中支持子控件的宽度可参考父控件的宽度以百分比设置,最外层控件的宽度参考屏幕尺寸以百分比设置。看过一些开源库使用类似的思路,来解决 Andoid 多机型适配的问题。但是,这些方案一般都有些缺点:会增加很多无用的数据,导致apk包变大,等等。
值得高兴的是,Google 提供了一个叫做 percent 的 Support 库,示例见这里 android-percent-support-lib-sample,上面的示例用的就是 percent 布局中的 PercentFrameLayout。
有了百分比布局那要实现上述效果就很简单了,关于代码没有什么好讲解的了,下面简单介绍下 percent 库。
percent Support 库简介
percent 库提供了两个布局:
PercentRelativeLayout、PercentFrameLayout,通过名字就可以看出,它们应该是从 FrameLayout 和 RelativeLayout 扩展而来的:
果然如此,FrameLayout 和 RelativeLayout 大家应该都很熟悉了,那了解下 PercentXxxLayout 提供的特有属性应该就可以用起来了。
PercentXxxLayout 特有属性:
- layout_widthPercent、layout_heightPercent
- layout_marginPercent
layout_marginLeftPercent
layout_marginTopPercent
layout_marginRightPercent
layout_marginBottomPercent
layout_marginStartPercent
layout_marginEndPercent
上面这些属性不用解释了吧!只是加了个 “Percent”,赋值的时候用 xx% 即可, 直接当作 FrameLayout、RelativeLayout 用就可以了。
简单使用
这里就不展开讲解了,感兴趣的,或者对该这两个布局不熟悉的可以参考:Android 百分比布局库(percent-support-lib) 解析与扩展
小结
weight 属性还是挺有作用的,利用好该属性可以避免使用硬编码的方式带来的副作用,但是它也有局限性 —— 只能在 LinearLayout 中使用。好在,我们现在有了更强大的百分比库了。
这只是布局技巧的冰山一角,还有很多技巧等待大家发掘,如果你有更好的方案,或者其他布局方面的技巧,希望也可以分享分享。
项目地址
AndroidHacks合集
布局篇
个人博客
示例用到代码见:
Hack1Activity.java
activity_hack1_1.xml
activity_hack1_2.xml
参考
Android 百分比布局库(percent-support-lib) 解析与扩展
android:layout_weight的真实含义
Android中 android:layout_weight 属性 完美解释