Android LineaLayout baselineAligned

来源:互联网 发布:如何选择床垫 知乎 编辑:程序博客网 时间:2024/06/15 21:55

首先看一个我遇到的问题,Layout如下

<?xml version="1.0" encoding="utf-8"?><RelativeLayout 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:padding="20dp"    tools:context="demo.cn.com.androidtest.MainActivity">    <LinearLayout        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:weightSum="3"        android:orientation="horizontal">        <Button            android:layout_width="0dp"            android:layout_height="50dp"            android:layout_weight="1"            android:text="Hello World! Hello World!"            />        <Button            android:layout_width="0dp"            android:layout_height="50dp"            android:layout_weight="1"            android:text="Hello World!"            />        <Button            android:layout_width="0dp"            android:layout_height="50dp"            android:layout_weight="1"            android:text="Hello World!"            />    </LinearLayout>   </RelativeLayout>

横着平均放三个Button,得到的显示结果如下


第一行由于内容比较多,按钮整体往下偏移了一点,但是Button属性都一样为什么会出现这种情况,我们给上面布局加上android:baselineAligned=false属性看一下效果

<?xml version="1.0" encoding="utf-8"?><RelativeLayout 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:padding="20dp"    tools:context="demo.cn.com.androidtest.MainActivity">    <LinearLayout        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:baselineAligned="false"        android:weightSum="3"        android:orientation="horizontal">        <Button            android:layout_width="0dp"            android:layout_height="50dp"            android:layout_weight="1"            android:text="Hello World! Hello World!"            />        <Button            android:layout_width="0dp"            android:layout_height="50dp"            android:layout_weight="1"            android:text="Hello World!"            />        <Button            android:layout_width="0dp"            android:layout_height="50dp"            android:layout_weight="1"            android:text="Hello World!"            />    </LinearLayout>   </RelativeLayout>

效果如下:

效果就是加上android:baselineAligned=false属性后,按钮的布局对齐了,这是我们需要的正常效果。

为什么会出现上述原因,让我们来分析一下android:baselineAligned的作用。


android:baselineAligned:基准对齐线,这个在中文中不常见,但在以字母为书写语言的其他国家非常常见如下图:


上面的那条红色的线就是基线。关于基线,有如下几点

1.首先这个基线主要是对可以显示文字的View,如TextView,Button等控件的

本例使用的是Button

2.这个baseline指的是这个UI控件的baseline--文字距UI控件顶部的偏移量,本例是距离顶部的偏移

3.LinearLayout控件默认有属性android:baselineAligned为true,如果LinearLayout的orientation为horizontal的话,其中的文字默认是文字对齐的,所以我们什么都不写,LinearLayout要求我们的文字的顶部对齐。这个我们查看源码也可得知

    /**     * Whether the children of this layout are baseline aligned.  Only applicable     * if {@link #mOrientation} is horizontal.     */    @ViewDebug.ExportedProperty(category = "layout")    private boolean mBaselineAligned = true;


如注释描述,只有是LinearLayout是水平的时候才生效,这个变量实际使用如下:

void measureHorizontal(int widthMeasureSpec, int heightMeasureSpec){   final int baselineAligned = mBaselineAligned; ......         if (widthMode == MeasureSpec.EXACTLY && lp.width == 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.                if (isExactly) {                    mTotalLength += lp.leftMargin + lp.rightMargin;                } else {                    final int totalLength = mTotalLength;                    mTotalLength = Math.max(totalLength, totalLength +                            lp.leftMargin + lp.rightMargin);                }                // Baseline alignment requires to measure widgets to obtain the                // baseline offset (in particular for TextViews). The following                // defeats the optimization mentioned above. Allow the child to                // use as much space as it wants because we can shrink things                // later (and re-measure).                if (baselineAligned) {                    final int freeSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);                    child.measure(freeSpec, freeSpec);                } else {                    skippedMeasure = true;            }                 ......}

LinearLayout是通过遍历孩子来给每一个孩子测量

如上源码实现:

if (widthMode == MeasureSpec.EXACTLY && lp.width == 0 && lp.weight > 0)刚好符合以本例,本里的测量过程会走这个分支

关键代码:

  if (baselineAligned) {                    final int freeSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);                    child.measure(freeSpec, freeSpec);                } else {                    skippedMeasure = true;            }
如果为true,则给其测量,如果为false就线略过,现在我们只需知道在水平方线上baselineAligned为true,测量的时候会特殊照顾就行,具体也不深挖了。

如下图,我们的基线为画出部分:


baselineAligned为true就要求文字对齐,为false的话则没有这个要求.




0 0