GridLayout使用要點總結

FannieChang 8年前發布 | 9K 次閱讀 安卓開發 Android開發 移動開發

GridLayout是在Android4.0中引進的新布局,使用它的理由有兩個:1,減少布局嵌套層次從而提高性能;2,對需要復雜對齊的布局,非他莫屬。不使用它的理由:由于太靈活導致學習難度比較大。本文是我研究GridLayout的心得要點。

一、GridLayout如何確定子View的坐標

對于一個n行m列的GridLayout,每個cell都有唯一的坐標(i,j),其中,i的取值區間為[0,n-1],j的取值坐標為[0,m-1]。所謂確定子View的坐標就是確定該子View所在的cell的坐標,如果子View占據了一個cell group,子View的坐標由cell group左上角的cell的坐標來確定,如圖所示:

coordinate-of-child-view.png

最簡單的情況就是利用子view的屬性android:layout_row和android:layout_column,這兩個屬性已經明白無誤地告訴GridLayout當前子View的坐標是什么。這沒什么好說的。

如果一個子View是如下三種情況之一,GridLayout就要幫助我們來確定子View的坐標:

  • 子View上既沒有android:layout_row屬性,也沒有android:layout_column屬性

  • 子View上只有android:layout_row屬性

  • 子View上只有android:layout_column屬性

google官方只有對第一種情況的說明:

Automatic Index Allocation

As children are added to a GridLayout, it maintains a cursor position and a “high-water mark” that it uses to place widgets in cells that don’t yet have anything in them.

milne-3.png

When GridLayout’s orientation property is horizontal

and a columnCoun t has been set (to 8 in this example) the high-water mark (shown above in red) is maintained as a separate height value for each column. When indices need to be created, GridLayout first determines the size of the cell group (by looking at the rowSpan and columnSpan parameters of the new widget) and then, starting at the cursor, goes through the available locations from: left to right, top to bottom, so as to find the row and column indices of the first location that’s free.

When GridLayout’s orientation is vertical

, all of the same principles apply, except that the roles of the horizontal and vertical axes are exchanged.

If you want multiple views to be placed in the same cell, you have to define the indices explicitly, as the default allocation procedure above is designed to place widgets in separate cells.

說的簡單,可是實際使用起來,完全不是這么回事!!

比如上文最后一句:

the default allocation procedure above is designed to place widgets in separate cells.

我實際測試中就發現了例外情況,并且在stackoverflow上提出來了。

如果有人能解決這個問題,希望能告訴我,謝謝!

另外,官方只說了GridLayout會給每一列維護一個high-water mark,并且維護一個全局的cursor position,可cursor position 到底怎么確定?有什么變化規律?經我實際測試,沒有什么規律,很容易搞亂。

最佳實踐:在實際使用中, 強烈建議 每一個子View都明確設置android:layout_row和android:layout_column,不要使用GridLayout的自動確定子View坐標功能。

二、GridLayout如何確定cell的寬高

假設我們給每一個子View都明確設置了row和column,還有rowSpan和columnSpan,此時GridLayout就可以確定每一行的高和每一列的寬,每一個cell的寬高也隨之確定。

GridLayout確定的寬高的算法是(以第1行和第1列為例):

  • 第1行的高:

    測量第1行中所有子View的高,取最大值作為該行的高,如果該行沒有子View,行高設為0。

  • 第1列的寬:

    測量第1列中所有子View的寬,取最大值作為該列的寬,如果該列沒有子View,列寬設為0。

這里有必要提示一下:GridLayout的子View不需要設置layout_width和layout_height屬性,因為GridLayout會把所有的子View的這兩個屬性設置為WRAP_CONTENT,所以你設置了也沒有用。

三、GridLayout如何利用剩余的空間

假如GridLayout布局完之后還有剩余的空間,如何分配這些空間呢?

多余的空間分兩種情況:橫向和縱向,我們以縱向為例:

假設分配完之后的布局是這樣的:

redunt.PNG

顯然,屏幕右邊還剩余一些空間。假設要把這些空間分給其他列,我們分三種情況討論:

  • 分給其中只有一個子View的單列

  • 分給其中有多個子View 的單列

  • 分給2個以上的列

1、 分給其中只有一個子View的單列

假設我們想把這些剩余的空間分配給“0505”(它實際上是一個TextView)所在的列。有兩個辦法:

  • 我們可以在TextView “0505”上添加這樣的設置:

    android:layout_gravity="fill_horizontal"

說明:此處的fill_horizontal還可以是center、center_horizontal、right、left,不能是其他值。

  • 我們還可以在TextView “0505”上添加這樣的設置:

    android:layout_columnWeight="1"

其中,weight的值可以隨意寫,反正只有這一列占用剩余的空間。

不管是用上面哪一種辦法,還是兩種都用,我們都可以達到目的,效果是這樣的:

noredunt.PNG

2、 分給其中有多個子View 的單列

如果我們想把多余的空間分配給“0404”和“1515”所在的列。那么對于每一個子View,即“0404”和“1515”。我們要不為它們添加android:layout_gravity="fill_horizontal"。

說明:此處的fill_horizontal仍然只能取center、center_horizontal、right、left。

要不為它們添加android:layout_columnWeight="1",其中,weight的值可以隨意寫,反正只有這一列占用剩余的空間。

也就是說,要在該列所有的子View上都添加上layout_gravity屬性或者layout_columnWeight屬性。

這里有一點容易讓人迷惑,就是如果我兩個子View都添加了layout_columnWeight,并且它們的值不一樣,這時會怎么樣呢?

如果是將剩余的空間全分配給這一列,那么兩個子View的column_Weight值是否相同是無所謂的。

但是對于第3種情況,也就是將多余的空間分給2個以上的列時,GridLayout只考慮兩個column_Weight中比較大的值。

最后的效果是這樣的:

multi_child_view.PNG

3、 分給2個以上的列

如果我們想把剩余的空間同時分給“0404”和“1515”所在列和“0505”所在列。這時情況就有點微妙了。這兩列不僅要滿足上面1和2中的條件,還有一個額外的限制:

每一列中至少有一個子View上設置了column_Weight屬性。

拿“0505”來說,此時它就不能只設置layout_gravity了,而是首先要設置column_Weight,layout_gravity是可加可不加的。

對于“0404”和“1515”所在列,就不能兩個子View都設置layout_gravity了,而是至少有一個上要設置column_Weight,當然可以兩個子View都設置column_Weight,此時只有二者中較大的值有效。

這個要求其實很好理解,因為我們要把多余的空間分給兩個列,所以我們必須告訴GridLayout,給各個列分配多余空間時的比例劃分。

4、Demo

使用GridLayout高仿的簡書首頁文章列表:

<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content">


        <TableRow
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <GridLayout
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:columnCount="4"
                android:rowCount="3">

                <com.example.milter.forgridlayoutblog.AvatarView
                    android:id="@+id/author_avatar"
                    android:layout_width="26.0dip"
                    android:layout_height="26.0dip"
                    android:layout_gravity="center"
                    android:scaleType="centerCrop"
                    android:src="@drawable/avatar"/>

                <TextView
                    android:id="@+id/author_name"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="bottom"
                    android:layout_marginLeft="8.0dip"
                    android:ellipsize="end"
                    android:maxWidth="200.0dip"
                    android:paddingBottom="10dp"
                    android:singleLine="true"
                    android:text="milter"
                    android:textColor="#ff4093c6"
                    android:textSize="12.0sp"/>

                <TextView
                    android:id="@+id/last_compiled_time"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="bottom"
                    android:layout_marginLeft="8.0dp"
                    android:paddingBottom="10dp"
                    android:singleLine="true"
                    android:text="2小時前"
                    android:textColor="@color/text_color_b1"
                    android:textSize="10.0sp"/>


                <TextView
                    android:id="@+id/title"
                    android:layout_column="0"
                    android:layout_columnSpan="4"
                    android:layout_row="1"
                    android:ellipsize="end"
                    android:lineSpacingExtra="2.0dip"
                    android:maxLines="2"
                    android:text="為什么要用GridLayout以及怎樣用GridLayout,為什么要用GridLayout以及怎樣用GridLayout"
                    android:textColor="@android:color/holo_purple"
                    android:textSize="16.0sp"/>

                <LinearLayout
                    android:layout_column="0"
                    android:layout_columnSpan="4"
                    android:layout_row="2">

                    <TextView
                        android:id="@+id/collection_tag"
                        android:layout_width="wrap_content"
                        android:layout_height="match_parent"
                        android:background="@drawable/shape_oval_h20_thin_theme"
                        android:gravity="center"
                        android:maxLength="10"
                        android:maxWidth="72dip"
                        android:minWidth="36.0dip"
                        android:text="程序員"
                        android:textColor="@color/theme_color"
                        android:textSize="10.0sp"/>

                    <TextView
                        android:id="@+id/extra_info"
                        android:layout_width="0dip"
                        android:layout_height="match_parent"
                        android:layout_marginLeft="8dp"
                        android:layout_weight="1"
                        android:drawablePadding="5.0dip"
                        android:ellipsize="marquee"
                        android:gravity="center"
                        android:lineSpacingExtra="2.0dip"
                        android:maxLines="1"
                        android:text="100次閱 ? 10評論 ? 100喜歡 ? 100打賞"
                        android:textColor="@color/text_color_b1"
                        android:textSize="10.0sp"
                        />

                </LinearLayout>


            </GridLayout>


            <ImageView
                android:id="@+id/image"
                android:layout_width="80dp"
                android:layout_height="80dp"
                android:layout_gravity="center"
                android:layout_marginLeft="5.0dip"
                android:scaleType="centerCrop"
                android:src="@drawable/image"
                android:visibility="visible"/>
        </TableRow>

        <View
            android:layout_width="match_parent"
            android:layout_height="0.39999998dip"
            android:layout_alignParentBottom="true"
            android:background="@android:color/holo_purple"
            android:paddingBottom="2dp"/>
    </TableLayout>
    <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content">


        <TableRow
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <GridLayout
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:columnCount="4"
                android:rowCount="3">

                <com.example.milter.forgridlayoutblog.AvatarView
                    android:id="@+id/author_avatar1"
                    android:layout_width="26.0dip"
                    android:layout_height="26.0dip"
                    android:layout_gravity="center"
                    android:scaleType="centerCrop"
                    android:src="@drawable/avatar"/>

                <TextView
                    android:id="@+id/author_name1"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="bottom"
                    android:layout_marginLeft="8.0dip"
                    android:ellipsize="end"
                    android:maxWidth="200.0dip"
                    android:paddingBottom="10dp"
                    android:singleLine="true"
                    android:text="milter"
                    android:textColor="#ff4093c6"
                    android:textSize="12.0sp"/>

                <TextView
                    android:id="@+id/last_compiled_time1"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="bottom"
                    android:layout_marginLeft="8.0dp"
                    android:paddingBottom="10dp"
                    android:singleLine="true"
                    android:text="2小時前"
                    android:textColor="@color/text_color_b1"
                    android:textSize="10.0sp"/>


                <TextView
                    android:id="@+id/title1"
                    android:layout_column="0"
                    android:layout_columnSpan="4"
                    android:layout_row="1"
                    android:ellipsize="end"
                    android:lineSpacingExtra="2.0dip"
                    android:maxLines="2"
                    android:text="為什么要用GridLayout以及怎樣用GridLayout,為什么要用GridLayout以及怎樣用GridLayout"
                    android:textColor="@android:color/holo_purple"
                    android:textSize="16.0sp"/>

                <LinearLayout
                    android:layout_column="0"
                    android:layout_columnSpan="4"
                    android:layout_row="2">

                    <TextView
                        android:id="@+id/collection_tag1"
                        android:layout_width="wrap_content"
                        android:layout_height="match_parent"
                        android:background="@drawable/shape_oval_h20_thin_theme"
                        android:gravity="center"
                        android:maxLength="10"
                        android:maxWidth="72dip"
                        android:minWidth="36.0dip"
                        android:text="程序員"
                        android:textColor="@color/theme_color"
                        android:textSize="10.0sp"/>

                    <TextView
                        android:id="@+id/extra_info1"
                        android:layout_width="0dip"
                        android:layout_height="match_parent"
                        android:layout_marginLeft="8dp"
                        android:layout_weight="1"
                        android:drawablePadding="5.0dip"
                        android:ellipsize="marquee"
                        android:gravity="center"
                        android:lineSpacingExtra="2.0dip"
                        android:maxLines="1"
                        android:text="100次閱 ? 10評論 ? 100喜歡 ? 100打賞"
                        android:textColor="@color/text_color_b1"
                        android:textSize="10.0sp"
                        />

                </LinearLayout>


            </GridLayout>


            <ImageView
                android:id="@+id/image1"
                android:layout_width="80dp"
                android:layout_height="80dp"
                android:layout_gravity="center"
                android:layout_marginLeft="5.0dip"
                android:scaleType="centerCrop"
                android:src="@drawable/image"
                android:visibility="visible"/>
        </TableRow>

        <View
            android:layout_width="match_parent"
            android:layout_height="0.39999998dip"
            android:layout_alignParentBottom="true"
            android:background="@android:color/holo_purple"
            android:paddingBottom="2dp"/>
    </TableLayout>

效果如下:

demo.PNG

 

 

來自:http://www.jianshu.com/p/441d60be7d8a

 

 本文由用戶 FannieChang 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!