Android技巧:学习使用GridLayout

GridLayout是一个非常强大的网格类布局,它不但能像TableLayout那样,实现网格类布局,但它更为强大的地方在于每个Cell的大小可以横向或者纵向拉伸,每个Cell的对齐方式也有很多种,而且不像TableLayout,需要一个TableRow,GridLayout可以通过指定Cell的坐标位置就能实现Cell的拉伸,从而实现,大小不一致的风格卡片式布局。

基本概念

GridLayout把页面分成m行和n列,使用m+1条线和n+1条线,把页面共分成n*m个Cell。指定位置时行坐标是从0到m,列坐标是从0到n。每一个子View占一个或多个Cell。比如(0, 0)到(0, 1)就是占第一个Cell的区域。(0, 0), (0, 2)就是占第一行的2个Cell的区域(横向拉伸).

使用方法

主要介绍一下如何添加Cell,以及设置Cell的位置和拉伸。其他的跟普通的ViewGroup没什么区别的,也没啥好说的。

GridLayout的基本设置

首先需要给GridLayout设置行数和列数:

  • android:columnCount 整数,最多的列数
  • android:rowCount 整数,最多的行数

在添加Cell就需要注意,不能超过设置的最大行数和列数,否则在添加Cell时会有异常。

元素Cell的位置控制

添加Cell时需要指定其位置

  • android:layout_column 整数n,在哪一列开始显示n=[0, 最大列-1]
  • android:layout_columnSpan 整数k,指定元素横跨几列,需要注意保证n+k <= 最大列数
  • android:layout_row 指定从哪一行开始显示,规则同列数
  • android:layout_rowSpan 纵向跨几行,规则同列

行高和列宽的确定

每一行的高度是由这一行中Cell的最大高度决定的,以及每一列的宽度是由每一列中最大的宽度决定的,小于行高和列宽的元素可以设置其对齐方式和填充方式。

填充方式

通过Cell的android:layout_gravity参数来指定,Cell的填充方式,注意仅当Cell元素本身的尺寸小于它所占格子的大小时才有效,比如元素本身尺寸小于行高和列宽,或者当它占多行,或者占多列时:

  • center -- 不改变元素的大小,仅居中
  • center_horizontal -- 不改变大小,水平居中
  • center_vertical -- 不改变大小,垂直居中
  • top -- 不改变大小,置于顶部
  • left -- 不改变大小,置于左边
  • bottom -- 不改变大小,置于底部
  • right -- 不改变大小,置于右边
  • start -- 不改变大小,置于开头(这个是与RTL从右向左读的文字有关的,如果使用start/end,那么当LTR文字时start=left,end=right,当RTL时start=right,end=left,也就是说系统会自动处理了)
  • end -- 不改变大小,置于结尾
  • fill -- 拉伸元素控件,填满其应该所占的格子
  • fill_vertical -- 仅垂直方向上拉伸填充
  • fill_horizontal -- 仅水平方向上拉伸填充
  • clip_vertical -- 垂直方向上裁剪元素,仅当元素大小超过格子的空间时
  • clip_horizontal -- 水平方向上裁剪元素,仅当元素大小超过格子的空间时

需要注意的是这些值是可以组合的,比如:

xml 复制代码
android:layout_gravity="center_vertical|clip_horizontal"

Cell之间的间距如何控制

默认间距

可以使用默认的间距android:useDefaultMargins="true"或者GridLayout#setUseDefaultMargins()。这个属性默认值是"false"。

另外一种方式就是跟普通布局管理器一样,给每个Cell设置其margins

通常如果不满意系统的默认间距,就可以设置useDefaultMargins="false",然后通过给Cell设置margin来控制间距。

居中方法

  • 仅有一个Cell或者仅有一行,或者仅有一列时

    当仅有一个子View时或者仅有一行或者一列的时候,可以把每个Cell设置其android:layout_gravitiy="center"(相应代码为LayoutParams#GravityCENTER),就可以让其在GridLayout中居中。

让一行居中:

xml 复制代码
    <GridLayout
        android:layout_width="wrap_content"
        android:layout_height="200dip"
        android:useDefaultMargins="true"
        android:background="@android:color/white"
        android:rowCount="1"
        android:columnCount="2">
        <Button android:layout_column="0"
            android:layout_row="0"
            android:text="Left Button"
            android:layout_gravity="fill_horizontal|center_vertical"/>
        <Button android:layout_column="1"
            android:layout_row="0"
            android:text="Right Button"
            android:layout_gravity="fill_horizontal|center_vertical"/>
    </GridLayout>
复制代码
让一个元素居中:
xml 复制代码
    <GridLayout
        android:layout_width="200dip"
        android:layout_height="200dip"
        android:useDefaultMargins="true"
        android:background="@android:color/white"
        android:rowCount="1"
        android:columnCount="1">
        <Button android:layout_column="0"
            android:layout_row="0"
            android:text="Left Button"
            android:layout_gravity="center"/>
    </GridLayout>
  • 其他情况

    其他情况,设置子View的Gravity就不再起作用了,这时最好的办法就是让GridLayout的高度是WRAP_CONTENT,然后让GridLayout在其父布局中居中。

xml 复制代码
     <LinearLayout
        android:layout_width="match_parent"
        android:orientation="vertical"
        android:gravity="center"
        android:background="@android:color/darker_gray"
        android:layout_height="200dip">
        <GridLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:useDefaultMargins="true"
            android:background="@android:color/white"
            android:rowCount="2"
            android:columnCount="2">
            <Button android:layout_column="0"
                android:layout_row="0"
                android:text="Left Button"
                android:layout_gravity="fill_horizontal|center_vertical"/>
            <Button android:layout_column="1"
                android:layout_row="0"
                android:text="Right Button"
                android:layout_gravity="fill_horizontal|center_vertical"/>
            <Button android:layout_column="1"
                android:layout_row="1"
                android:text="Right Button 2"
                android:layout_gravity="fill_horizontal|center_vertical"/>
        </GridLayout>
    </LinearLayout>

适用场景

GridLayout虽然强大,可以当作LinearLayout使用,也可以当作RelativeLayout使用,甚至也能当FrameLayout使用。但是,我们不可以滥用,对于任意布局都一样,不能是它能实现需求就使用它,而是要根据实际的需求,选择最简单,最方便的,同时也要考虑性能。

通常对于类似于网格的布局就可以考虑用GridLayout来实现,或者用LinearLayout横七竖八的套了好几层时也要考虑使用GridLayout。

GridLayout vs GridView or RecyclerView

当要实现网格布局,或者非均匀风格布局时,可能首先想到的就是GridView,但是这也要看实际的情况而定。GridView,ListView以及RecyclerView是用于无限长度列表或者网格的场景,它们最大的特点是无限长度,因此这几个组件的重点在于如何复用Cell以提升性能,以及处理手势事件(Fling)等。所以,每当遇到列表或者网格的时候,先想一下这个长度大概会是多少,如果是在百个以内,且不会随时增长,这时就可以考虑使用静态(非动态复用)的组件比如LinearLayout或者GridLayout来实现。

实例

说的太多都是废话,来一个实例感觉一下子是最直接的:

xml 复制代码
<GridLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:background="@android:color/white"
            android:alignmentMode="alignMargins"
            android:useDefaultMargins="true"
            android:columnCount="4"
            android:rowCount="5"
            android:visibility="visible">
            <Button android:layout_column="0"
                android:layout_row="0"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="10dip"
                android:text="1"/>
            <Button android:layout_column="1"
                android:layout_row="0"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="10dip"
                android:text="2"/>
            <Button android:layout_column="2"
                android:layout_row="0"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="10dip"
                android:text="3"/>
            <Button android:layout_column="0"
                android:layout_row="1"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="10dip"
                android:text="4"/>
            <Button android:layout_column="1"
                android:layout_row="1"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="10dip"
                android:text="5"/>
            <Button android:layout_column="2"
                android:layout_row="1"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="10dip"
                android:text="6"/>
            <Button android:layout_column="0"
                android:layout_row="2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="10dip"
                android:text="7"/>
            <Button android:layout_column="1"
                android:layout_row="2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="10dip"
                android:text="8"/>
            <Button android:layout_column="2"
                android:layout_row="2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="10dip"
                android:text="9"/>
            <Button android:layout_column="0"
                android:layout_row="3"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="10dip"
                android:text="0"/>
            <Button android:layout_column="1"
                android:layout_row="3"
                android:layout_gravity="fill_horizontal"
                android:layout_columnSpan="2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:padding="10dip"
                android:text="Delete"/>
            <Button android:layout_column="0"
                android:layout_row="4"
                android:layout_columnSpan="2"
                android:layout_gravity="fill_horizontal"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="10dip"
                android:text="Clear"/>
            <Button android:layout_column="2"
                android:layout_row="4"
                android:layout_columnSpan="2"
                android:layout_gravity="fill_horizontal"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:padding="10dip"
                android:text="="/>
            <Button android:layout_column="3"
                android:layout_row="0"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="fill"
                android:padding="10dip"
                android:text="+"/>
            <Button android:layout_column="3"
                android:layout_row="1"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="fill"
                android:padding="10dip"
                android:text="-"/>
            <Button android:layout_column="3"
                android:layout_row="2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="fill"
                android:padding="10dip"
                android:text="*"/>
            <Button android:layout_column="3"
                android:layout_row="3"
                android:layout_columnSpan="1"
                android:layout_gravity="fill"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:padding="10dip"
                android:text="/"/>
        </GridLayout>

参考资料

欢迎搜索并关注 公众号「稀有猿诉」 获取更多的优质文章!

保护原创,请勿转载!

相关推荐
莞凰21 小时前
昇腾CANN的“灵脉根基“:Runtime仓库探秘
android·人工智能·transformer
NiceCloud喜云1 天前
Claude Files API 深入:从上传、复用到配额管理的工程化指南
android·java·数据库·人工智能·python·json·飞书
ujainu1 天前
CANN pto-isa:虚拟指令集如何连接编译与执行
android·ascend
赏金术士1 天前
第六章:UI组件与Material3主题
android·ui·kotlin·compose
TechMerger1 天前
Android 17 重磅重构!服役 20 年的 MessageQueue 迎来无锁改造,卡顿大幅优化!
android·性能优化
yuhuofei20211 天前
【Python入门】Python中字符串相关拓展
android·java·python
dalancon1 天前
Android Input Spy Window
android
dalancon1 天前
InputDispatcher派发事件,查找目标窗口
android
我命由我123451 天前
Android Framework P3 - MediaServer 进程、认识 ServiceManager 进程
android·c语言·开发语言·c++·visualstudio·visual studio·android runtime
天才少年曾牛1 天前
Android14 新增系统服务后,应用调用出现 “hidden api” 警告的原因与解决方案
android·frameworks