在上一篇文章里,我总结了一下自定义控件需要了解的基础知识:View的绘制流程——《自定义控件知识储备-View的绘制流程》。其中,在View的测量流程里,View的测量宽高是由父控件的MeasureSpec和View自身的LayoutParams共同决定的。MeasureSpec是什么,上一篇文章里已经说得很清楚了(啥,没看过?快去路克路克,(๑•̀ㅂ•́)و✧)。而LayoutParams呢?是时候在这里做个了断了。
LayoutParams是什么?
LayoutParams,顾名思义,就是Layout Parameters :布局参数。
很久很久以前,我就知道LayoutParams了,并且几乎天天见面。那时候在布局文件XML里,写的最多的肯定是android:layout_width = "match_parent"
之类的了。比如:
<TextView
style="@style/text_flag_01"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginLeft="10dp"
android:layout_gravity="center"
android:gravity="center"
android:text="英明神武蘑菇君"
android:textColor="@color/white"
android:background="@color/colorAccent"/>
我们都知道layout_width
和layout_height
这两个属性是为View指定宽度的。不过,当时年轻的我心里一直有个疑问:为什么要加上”layout_”前缀修饰呢?其它的描述属性,如textColor
和background
,都很正常啊!讲道理,应该用width
和height
描述宽高才对啊?
后来呀,我遇到了LayoutParams,它说layout_width
是它的属性而非View的,并且不只是针对这一个,而是所有以”layout_”开头的属性都与它有关!所以,它的东西当然要打上自己的标识”layout_”。(呵呵,嚣张个啥,到头来你自己还不是属于View的一部分( ̄┰ ̄*))
既然layout_width
这样的属性是LayoutParams定义的,那为何会出现在描述View的xml属性里呢?View和LayoutParams之间有什么恩怨纠缠呢?
不吹不黑,咱们来看看官方文档是怎么说的:
LayoutParams are used by views to tell their parents how they want to be laid out.
– LayoutParams是View用来告诉它的父控件如何放置自己的。The base LayoutParams class just describes how big the view wants to be for both width and height.
– 基类LayoutParams(也就是ViewGroup.LayoutParams)仅仅描述了这个View想要的宽度和高度。There are subclasses of LayoutParams for different subclasses of ViewGroup.
– 不同ViewGroup的继承类对应着不同的ViewGroup.LayoutParams的子类。
看着我妙到巅峰的翻译,想必大家都看懂了<( ̄▽ ̄)/。看不懂?那我再来画蛇添足稍微解释一下:
上面我们提到过,描述View直接用它们自己的属性就好了,如
textColor
和background
等等,为什么还需要引入LayoutParams呢?在我看来,textColor
和background
这样的属性都是只与TextView自身有关的,无论这个TextView处于什么环境,这些属性都是不变的。而layout_width
与layout_marginLeft
这样的属性是与它的父控件息息相关的,是父控件通过LayoutParams提供这些”layout_”属性给孩子们用的;是父控件根据孩子们的要求(LayoutParams)来决定怎么测量,怎么安放孩子们的;是父控件……(写不下去了,我都快被父控件感动了,不得不再感慨一句,当父母的都不容易啊(′⌒`)) )。所以,View的LayoutParams离开了父控件,就没有意义了。基类LayoutParams是ViewGroup类里的一个静态内部类(看吧,这就证明了LayoutParams是与父控件直接相关的),它的功能很简单,只提供了
width
和height
两个属性,对应于xml里的layout_width
和layout_height
。所以,对任意系统提供的容器控件或者是自定义的ViewGroup,其chid view总是能写layout_width
和layout_height
属性的。自从有了
ViewGroup.LayoutParams
后,我们就可以在自定义ViewGroup时,根据自己的逻辑实现自己的LayoutParams,为孩子们提供更多的布局属性。不用说,系统里提供给我们的容器控件辣么多,肯定也有很多LayoutParams的子类啦。let us see see:
果然,我们看到了很多ViewGroup.LayoutParams
的子类,里面大部分我们应该都比较熟悉。如果你觉得和它们不熟,那就是你一厢情愿啦,你早就“偷偷摸摸”的用过它们好多次了→_→
ViewGroup.MarginLayoutParams
我们首先来看看ViewGroup.MarginLayoutParams
,看名字我们也能猜到,它是用来提供margin属性滴。margin属性也是我们在布局时经常用到的。看看这个类里面的属性:
public static class MarginLayoutParams extends ViewGroup.LayoutParams {
public int leftMargin;
public int topMargin;
public int rightMargin;
public int bottomMargin;
private int startMargin = DEFAULT_MARGIN_RELATIVE;
private int endMargin = DEFAULT_MARGIN_RELATIVE;
...
}
前面4个属性是我们以前在布局文件里常用的,而后面的startMargin
和endMargin
是为了支持RTL设计出来代替leftMargin
和rightMargin
的。
一般情况下,View开始部分就是左边,但是有的语言目前为止还是按照从右往左的顺序来书写的,例如阿拉伯语。在Android 4.2系统之后,Google在Android中引入了RTL布局,更好的支持了从右往左文字布局的显示。为了更好的兼容RTL布局ÿ