鸿蒙0基础探索,第二篇:使用网格Grid与列表list

213 阅读9分钟

第二篇:使用网格Grid与列表list

背景:鸿蒙0基础探索。

愿景:本系列旨在用简单直接的方式从让鸿蒙app先从0-1。

理由:有产出更有继续下去的动力。

记录:每篇文章保留下探索的过程。

PS:  不教写代码,不封装,业务代码能力因人而异。(关键我不会啊😁)

第一篇:创建一个应用,使用Tabs和导航栏结构

第二篇:使用网格Grid与列表list

第三篇:接入第三方库,使用Axios网络请求,PullToRefresh上拉刷新下拉加载

第四篇:整理工程 - 模块化

第五篇:探索打包提审上架

书接上回。我们有了tabs和导航栏之后,立马就开始探索“列表”在鸿蒙中是用什么。为什么是探索这个,因为它实在是太被常用了,一个APP大部分的页面都多少离不开列表。(你要相信像Button, label,if,不会成为探索路上的拦路虎,我学会了列表,那些东西很轻松就能学会)。

我们在上一篇典型应用场景中同时也发现了网格,轮播等。自然就发现,在鸿蒙中可以通过Grid和List实现"列表"的功能

探索中遇到的痛点

痛点一:编译器参数提示

参数提示,不知道有哪些参数能写。用习惯Xcode的,参数会跟着方法一起出来,还不适应每写一个方法都要跳进定义里找,有的参数套几层,跳来跳去,给自己跳晕了,不知道自己要干嘛了。(不过咨询了一下,安卓开发好像一直是这样,那估计这一点编译器支持不了,去习惯它,如果有请大佬告诉我下)。

痛点二:编译器内⌘ + 左键:查看参数定义(windows快捷键好像control + 左键),后面发了新的查看方式,就好用很多 ⌘ + 7

看定义详情,注释太长,分了各个api的版本,真的看不清楚一个实例到底有哪些功能。 对阅读源码接口定义真的很不友好。

举个例子:点击了Grid() {}的定义,点进来看到的全是注释。这样的例子充斥着整个文档。 image.png

咨询了同事,Android Studio中是否有查看页面的方法参数定义的一个快捷浏览。以此来推测DevEco-Studio是否有。于是乎找到了这个Navigate -> File Structure(文件结构),我们还是拿Grid的定义举例。, 看后面不错的新的方式

下面这个是我结合定义猜的,应该大差不差。如果单词拼写错误,请忽略,意会了就行

类相关:

  • C: 抽象类:class。
  • I: 实体类:Interface
  • E: 枚举:Enum

方法相关:

  • m: 修改器/装饰器: modifier
  • p: 属性/参数: param/property
  • 黄色f: 枚举的值,词汇量有限,不知道哪个英文词
  • 红色f:方法:function

Snipaste_2024-08-23_16-09-50.png

通过这个,来查看定义绝对比查看api文档快上很多,而且熟练以后更多是在编译上查看,不会经常打开网页去查。

ps:这个功能是有了,就是吧:这个交互上实在不好用。 希望编译器团队优化优化。 顺便再提点建议,希望能鼠标悬停在类上时,弹出的提示里,能直接给上几段示例代码。参考SwiftUI。

痛点二替代方案: 我们来看看后来发现的 ⌘ + 7

我们后来发现Structrue。这东西,然后把他固定在了右边。里面还有一个view Mode的配置。可以调整悬浮窗等,看个人习惯,去试试吧。

image.png

以m: modifier为例,有些英文一眼就能看出是干什么的,比如minCout,maxCount,rowsGap,columnsGap.

Grid() {
}
// 那我就可以这样设置行间距
.rowsGap(10)

相关概念

去看Grid的相关资料时,自然而然引出了。Grid,GirdItem,ForEach(支持渲染控制类型之一,推荐先了解这种,够常用。 LazyForEach和Repeat看个人状态,我没看,等以后遇到了看也来得及)。

列表List。 官方文档链接

网格布局Grid 官方文档链接

文档看的还是一头包,主要是文档示例代码都半截子,没办法还原示例。

文档中穿插的额几个说明,不用急着理解,记录一下。

说明 当Grid组件设置了rowsTemplate或columnsTemplate时,Grid的layoutDirection、maxCount、minCount、cellLength属性不生效,属性说明可参考Grid-属性

说明 Grid的子组件必须是GridItem组件。

说明 Grid组件根据行列数量与占比属性的设置,可以分为三种布局情况:

  • rowsTemplate,columnsTemplate同时设置:Grid只展示固定行列数的元素,其余元素不展示,且Grid不可滚动。(推荐使用该种布局方式)
  • 只设置rowsTemplate:可横向滚动
  • 只设置columnsTemplate:可纵向滚动。
  • 都不设置:元素在布局方向上排布,其行列数由布局方向、单个网格的宽高等多个属性共同决定。超出行列容纳范围的元素不展示,且Grid不可滚动。

自定义GridItem的所占行列数

看文档的时候肯定有很多困惑,比如要自定义某个item的宽高,设置设置子组件所占行列数

看不懂,困惑的点:

1.我怎么知道Grid能设置GridLayoutOptions这个。

2.Grid里还有什么参数可以设置。

3.GridLayoutOptions这里面又有哪些能设置。

我们在痛点2中提到的方法就派上用场了。 image.png 1.Grid对象只提供了一个方法初始化,有且只有两个?(可选)参数。所以我们可以用Grid() {}这样的写法初始化。

2.我再看看GridLayoutOptions的几个参数,3个可选,1个regularSize是必填, 类型为一个number[]数组,有两个值。所以可以这样写:

// 所以初始化GridLayoutOptions至少要有regularSize参数。
layoutOptions: GridLayoutOptions = {
  // 常规item的宽高
  regularSize: [1, 1],
}

3.我们在图上看看,文档上要我们使用的onGetRectByIndex是如何定义的。给了一个index的参数,类型是number. 需要我们返回一个numbers[]数组,有4个值。于是乎可以这样写一定不会报错:(下一步研究这几个值代表是什么意思)

layoutOptions: GridLayoutOptions = {
  // 常规item的宽高
  regularSize: [1, 1],
  // 设置rect通过下标。
  onGetRectByIndex: (index: number) => {
    return [0, 0, 1, 1]
  }
}

4.先通过名字onGetRectByIndex大概猜一下:“读取,位置信息,通过,下标”。所以里面取值大概是是能表示位置信息的。这时候我们就点进这个参数看注释。[rowStart, columnStart, rowSpan, columnSpan] image.png

如果还有困惑,就再去官方文档上再看看中文解释,相信一定会有收获。[起始行, 起始列, 要占几行, 要占几列]。 如果你也是iOS的话,理解为frame(x:, y:, width: , height:)就挺好理解。这样我们就可以结合index参数,为某一些item设置特殊位置。

据我观察:使用GridLayoutOptions配置时Grid时,需要指明. 行模板:rowsTemplate, 列模板columnsTemplate。相当于知道了有 几行几列,才好设置特殊的大小GridItem。

比如我这个4行4列的grid:注意看图上数据对应排列的位置。 Snipaste_2024-08-23_12-02-42.png

提问:如果我把下标为4的格子,宽度改占3列。 明显4和6所占的位置会打架,那会发生什么。

修改
 else if (index == 4) {
  return [2, 0, 1, 3]
}

Snipaste_2024-08-23_12-06-36.png 由此我猜测应该是这样:,onGetRectByIndex执行的顺序会从上往下开始排,谁写前面先排谁。 当我index == 1,index == 4排完之后。 遇到了index == 6,发现4和6的位置是冲突的。那6就会去走常规布局

横向滑动

需要设置 行模板rowsTemplate,最好也指定个width。

点击展开代码
@Entry
@Component
export struct RankPage {
  // 数据源,
  modelArray: string[] = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]

  build() {
    Grid() {
      ForEach(this.modelArray, (item: string, index) => {
        // 在这里面构建每一个item的布局。 GridItem相当于iOS中: UITableViewCell / UIColletionViewCell
        GridItem() {
          Text(item)
            .backgroundColor(Color.White)
        }
        .width('25%')
        .backgroundColor(Color.Pink)

      })
    }
    // 比如我指定了高度,不指定就默认充满父视图。
    .height(300)
    // 行的模板
    .rowsTemplate('1fr 1fr')
    // 设置列间距
    .columnsGap(10)
    // 设置行间距
    .rowsGap(25)
    .backgroundColor(Color.Yellow)
  }
}

纵向滑动

需要设置 列模板columnsTemplate,最好也指定个height。

点击展开代码
@Entry
@Component
export struct RankPage {
  // 数据源,
  modelArray: string[] = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]

  build() {
    Grid() {
      ForEach(this.modelArray, (item: string, index) => {
        // 在这里面构建每一个item的布局。 GridItem相当于iOS中: UITableViewCell / UIColletionViewCell
        GridItem() {
          Text(item)
            .backgroundColor(Color.White)
        }
        .height('25%')
        .backgroundColor(Color.Pink)

      })
    }
    // 比如我指定了高度,不指定就默认充满父视图。
    .height(300)
    // 列的模板
    .columnsTemplate('1fr 1fr')
    // 设置列间距
    .columnsGap(10)
    // 设置行间距
    .rowsGap(25)
    .backgroundColor(Color.Yellow)
  }
}

计算器布局示例

补充了一下文档中的示例代码。数据源modelArray可以是自定义了对象,为了方便演示简化了。

需要注意的是图上,第一块粉色区域,占1行4列,配合rowsTemplate第一行的2fr,代表占了2份高度。 fr是用 空格 分隔的,不是逗号。

image.png

点击展开代码
@Entry
@Component
export struct RankPage {
  // 数据源,
  modelArray: string[] = [
    "",
    "CE", "C", "/", "X",
    "7", "8", "9", "-",
    "4", "5", "6", "+",
    "1", "2", "3", "=",
    "0", "."]

  layoutOptions: GridLayoutOptions = {
    regularSize: [1, 1],
    onGetRectByIndex: (index: number) => {
      if (index == 0) { // 第一个空字符串相当于结果展示位 占了1行4列。(第一行的高度是2fr)
        return [0, 0, 1, 4]
      } else if (index == 16) { // "="号,占2行一列
        return [4, 3, 2, 1]
      } else if (index == 17) { // "0"号,占1行两列
        return [5, 0, 1, 2]
      }

      return [0, 0, 1 , 1]
    }
  }

  build() {
    Grid(undefined ,this.layoutOptions) {
      ForEach(this.modelArray, (item: string, index) => {
        // 在这里面构建每一个item的布局。 GridItem相当于iOS中: UITableViewCell / UIColletionViewCell
        GridItem() {
          Text(item)
            .backgroundColor(Color.White)
        }
        .backgroundColor(Color.Pink)

      })
    }
    // 比如我指定了高度,不指定就默认充满父视图。
    .height(400)
    // 行的模板
    .rowsTemplate('2fr 1fr 1fr 1fr 1fr 1fr')
    .columnsTemplate('1fr 1fr 1fr 1fr')
    // 设置列间距
    .columnsGap(10)
    // 设置行间距
    .rowsGap(10)
    .backgroundColor(Color.Yellow)
  }
}

列表布局list 官方文档链接

关于list的探索,就交给各位自己了,木有问题。

这一期做的效果

决定结合上一期我们学到的tabs标签栏, 结合Grid,顺便加上轮播Swiper,做一个宝可梦列表的练手的效果。

  • swiper轮播图 官方文档
  • image 官方文档,至少需要了解加载本地图片,网络图片,图片缩放类型objectFit

看看效果

录屏2024-08-26 19.07.21.gif

Demo代码

最后附上demo地址,第二篇内容,把用得上几个文件拷进自己新建的工程就行。别忘了module.json5里加 "routerMap": "$profile:route_map",。 还有route_map.json文件别忘了。