项目演示

在这里插入图片描述
在这里插入图片描述

一、引言

在移动应用开发中,网格布局(Grid Layout)是一种非常常见的布局方式,广泛应用于图片画廊、商品列表、数据展示等场景。随着用户对应用体验要求的不断提高,滚动条的样式和交互也成为影响用户体验的重要因素。

HarmonyOS NEXT作为华为新一代智能终端操作系统,提供了丰富的UI组件和布局能力。其中,Grid组件和scrollBar相关属性的组合使用,为开发者提供了强大的网格滚动布局解决方案。

本文将深入探讨鸿蒙原生ArkTS布局方式之Grid+scrollBar滚动条布局,从概念介绍、API详解、代码实现到性能优化,全面解析这一核心技术。


二、Grid组件概述

2.1 Grid组件定义与作用

Grid组件是HarmonyOS ArkUI框架中用于实现网格布局的核心容器组件。它将子组件按照行列的方式排列,形成规则的网格结构。

Grid组件的主要特点:

  • 规则排列:子组件按照行列规则排列,形成整齐的网格结构
  • 灵活配置:支持自定义列数、行数、间距等属性
  • 自动滚动:当内容超出容器范围时,自动支持滚动功能
  • 响应式布局:支持根据屏幕尺寸动态调整列数和布局

Grid组件的应用场景:

  • 图片画廊:如相册应用中的照片网格展示
  • 商品列表:电商应用中的商品网格展示
  • 数据表格:数据密集型应用中的数据展示
  • 仪表盘:智能家居控制面板的布局

2.2 Grid组件核心属性

2.2.1 列配置属性

columnsTemplate

用于定义网格的列模板,决定网格的列数和每列的宽度分配方式。

Grid() {
  // GridItem子组件
}
.columnsTemplate('1fr 1fr 1fr') // 3列等宽分布

columnsGap

用于设置列与列之间的间距。

Grid() {
  // GridItem子组件
}
.columnsGap(10) // 列间距10vp
2.2.2 行配置属性

rowsGap

用于设置行与行之间的间距。

Grid() {
  // GridItem子组件
}
.rowsGap(10) // 行间距10vp

rowHeight

用于设置每行的高度。

Grid() {
  // GridItem子组件
}
.rowHeight(100) // 每行高度100vp
2.2.3 尺寸与滚动属性

width

设置Grid容器的宽度。

Grid() {
  // GridItem子组件
}
.width('100%') // 宽度占满父容器

height

设置Grid容器的高度,这是触发滚动的关键属性。

Grid() {
  // GridItem子组件
}
.height(500) // 固定高度500vp,超出部分可滚动

重要提示:Grid组件只有设置了固定高度(如500vp)或百分比高度,并且内容高度超过容器高度时,才会触发滚动效果。如果不设置高度,Grid会自适应内容高度,不会产生滚动。

2.3 GridItem组件

GridItem是Grid组件的子组件,用于表示网格中的每个单元格。

Grid() {
  GridItem() {
    // 单元格内容
    Column() {
      Text('网格项')
        .fontSize(16);
    }
  }
  .height(100) // 设置单元格高度
  .backgroundColor('#e3f2fd') // 设置背景色
}

三、scrollBar滚动条属性详解

3.1 scrollBar属性概述

scrollBar属性是滚动组件(包括Grid、List、Scroll、WaterFlow)的通用属性,用于控制滚动条的显示状态。

API Level支持: 从API version 8开始支持

属性类型: BarState枚举

BarState枚举值:

枚举值 说明
BarState.Auto 滚动条自动显示/隐藏(滚动时显示,停止时隐藏)
BarState.On 始终显示滚动条
BarState.Off 始终隐藏滚动条

3.2 scrollBar属性使用方式

Grid() {
  // GridItem子组件
}
.height(500)
.scrollBar(BarState.Auto) // 滚动时显示,停止时隐藏

3.3 scrollBarWidth属性

用于设置滚动条的宽度。

API Level支持: 从API version 11开始支持

Grid() {
  // GridItem子组件
}
.height(500)
.scrollBar(BarState.Auto)
.scrollBarWidth(8) // 滚动条宽度8vp

3.4 scrollBarColor属性

用于设置滚动条滑块的颜色。

API Level支持: 从API version 11开始支持

Grid() {
  // GridItem子组件
}
.height(500)
.scrollBar(BarState.Auto)
.scrollBarColor('#2196f3') // 滚动条颜色为蓝色

3.5 scrollBarMargin属性

用于设置滚动条与组件边缘的距离。

API Level支持: 从API version 20开始支持

Grid() {
  // GridItem子组件
}
.height(500)
.scrollBar(BarState.Auto)
.scrollBarMargin({ top: 10, bottom: 10 }) // 上下边距各10vp

3.6 滚动事件

Grid组件支持多种滚动事件,用于监听滚动状态变化。

3.6.1 onScrollStart

滚动开始时触发。

API Level支持: 从API version 11开始支持

Grid() {
  // GridItem子组件
}
.height(500)
.onScrollStart(() => {
  console.info('滚动开始');
})
3.6.2 onScrollStop

滚动停止时触发。

API Level支持: 从API version 11开始支持

Grid() {
  // GridItem子组件
}
.height(500)
.onScrollStop(() => {
  console.info('滚动停止');
})
3.6.3 onReachStart

滚动到起始位置时触发。

API Level支持: 从API version 11开始支持

Grid() {
  // GridItem子组件
}
.height(500)
.onReachStart(() => {
  console.info('已滚动到顶部');
})
3.6.4 onReachEnd

滚动到末尾位置时触发。

API Level支持: 从API version 11开始支持

Grid() {
  // GridItem子组件
}
.height(500)
.onReachEnd(() => {
  console.info('已滚动到底部');
})
3.6.5 onDidScroll

滚动过程中触发,返回当前滚动偏移量。

API Level支持: 从API version 12开始支持

Grid() {
  // GridItem子组件
}
.height(500)
.onDidScroll((scrollOffset: number, scrollState: ScrollState) => {
  console.info(`当前滚动偏移量: ${scrollOffset}`);
  console.info(`滚动状态: ${scrollState}`);
})

四、Grid+scrollBar布局完整实现示例

4.1 示例场景描述

本示例实现一个大型网格滚动显示场景,包含以下功能:

  1. 展示100个网格项的4列网格布局
  2. 支持滚动条显示状态切换(Auto/On/Off)
  3. 支持滚动条颜色切换
  4. 展示滚动条宽度自定义效果

4.2 完整代码实现

/**
 * @Entry 装饰器标记这是一个应用的入口页面
 * @Component 装饰器标记这是一个自定义组件
 * 
 * 本示例展示鸿蒙原生ArkTS布局方式之Grid + scrollBar滚动条布局
 * 场景:大型网格滚动显示
 * 核心技术:Grid组件 + scrollBar属性 + height属性配合实现滚动效果
 */
@Entry
@Component
struct GridScrollBarExample {
  /**
   * @State 装饰器标记状态变量,当变量值改变时会触发UI刷新
   * 模拟大型网格数据,创建100个网格项
   */
  @State gridData: number[] = this.createGridData();

  /**
   * @State 滚动条显示状态,默认为Auto
   * BarState.Auto:滚动时显示,停止时隐藏
   * BarState.On:始终显示滚动条
   * BarState.Off:始终隐藏滚动条
   */
  @State currentBarState: BarState = BarState.Auto;

  /**
   * @State 滚动条颜色数组,用于切换演示
   */
  @State barColors: string[] = ['#2196f3', '#4caf50', '#ff9800', '#f44336'];

  /**
   * @State 当前选中的滚动条颜色索引
   */
  @State currentColorIndex: number = 0;

  /**
   * @State 当前选中的滚动条状态索引
   */
  @State currentStateIndex: number = 0;

  /**
   * 滚动条状态名称数组,用于按钮显示
   */
  private barStateNames: string[] = ['Auto', 'On', 'Off'];

  /**
   * 滚动条状态值数组
   */
  private barStateValues: BarState[] = [BarState.Auto, BarState.On, BarState.Off];

  /**
   * 创建网格数据
   * ArkTS不支持Array.from,需要手动创建数组
   */
  private createGridData(): number[] {
    let data: number[] = [];
    for (let i = 0; i < 100; i++) {
      data.push(i + 1);
    }
    return data;
  }

  /**
   * 切换滚动条状态
   */
  private toggleBarState(): void {
    this.currentStateIndex = (this.currentStateIndex + 1) % this.barStateValues.length;
    this.currentBarState = this.barStateValues[this.currentStateIndex];
  }

  /**
   * 切换滚动条颜色
   */
  private toggleBarColor(): void {
    this.currentColorIndex = (this.currentColorIndex + 1) % this.barColors.length;
  }

  /**
   * build()方法是组件的构建函数,用于描述UI结构
   */
  build() {
    /**
     * 使用Column作为根容器,采用垂直布局
     * height('100%')和width('100%')使容器占满整个屏幕
     */
    Column() {
      /**
       * 页面标题区域
       * 设置背景色和内边距,增强视觉效果
       */
      Text('Grid + ScrollBar 滚动条布局示例')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .padding({ top: 20, bottom: 15 })
        .width('100%')
        .textAlign(TextAlign.Center)
        .backgroundColor('#f0f0f0');

      /**
       * 控制面板区域
       * 提供交互式按钮,演示滚动条状态和颜色切换
       */
      Row() {
        /**
         * 滚动条状态切换按钮
         */
        Column() {
          Text('滚动条状态')
            .fontSize(14)
            .fontWeight(FontWeight.Medium)
            .margin({ bottom: 8 });

          Text(`当前: ${this.barStateNames[this.currentStateIndex]}`)
            .fontSize(12)
            .opacity(0.7)
            .margin({ bottom: 8 });

          Button('切换状态')
            .width(120)
            .height(40)
            .backgroundColor('#2196f3')
            .fontColor('#ffffff')
            .borderRadius(8)
            .onClick(() => {
              this.toggleBarState();
            });
        }
        .flexGrow(1)
        .alignItems(HorizontalAlign.Center);

        /**
         * 分隔线
         */
        Divider()
          .vertical(true)
          .width(1)
          .color('#e0e0e0');

        /**
         * 滚动条颜色切换按钮
         */
        Column() {
          Text('滚动条颜色')
            .fontSize(14)
            .fontWeight(FontWeight.Medium)
            .margin({ bottom: 8 });

          /**
           * 颜色指示器
           */
          Row() {
            Text('当前颜色:')
              .fontSize(12)
              .opacity(0.7);

            Blank()
              .width(10);

            Stack() {
              Text('')
                .width(20)
                .height(20)
                .backgroundColor(this.barColors[this.currentColorIndex])
                .borderRadius(4);
            }
            .margin({ bottom: 8 });
          }
          .width('100%')
          .justifyContent(FlexAlign.Center);

          Button('切换颜色')
            .width(120)
            .height(40)
            .backgroundColor('#2196f3')
            .fontColor('#ffffff')
            .borderRadius(8)
            .onClick(() => {
              this.toggleBarColor();
            });
        }
        .flexGrow(1)
        .alignItems(HorizontalAlign.Center);
      }
      .width('100%')
      .padding({ top: 15, bottom: 15, left: 20, right: 20 })
      .backgroundColor('#ffffff');

      /**
       * Grid组件:网格布局容器
       * 
       * 关键属性说明:
       * 1. height('500vp'):设置固定高度,这是触发滚动的关键条件
       *    - 当Grid内容高度超过容器高度时,才会出现滚动条
       *    - 如果不设置固定高度,Grid会自适应内容高度,不会产生滚动
       * 
       * 2. scrollBar(BarState.Auto):控制滚动条显示状态
       *    - BarState.Auto:滚动条自动显示/隐藏(滚动时显示,停止时隐藏)
       *    - BarState.On:始终显示滚动条
       *    - BarState.Off:始终隐藏滚动条
       * 
       * 3. scrollBarWidth():设置滚动条宽度
       * 
       * 4. scrollBarColor():设置滚动条滑块颜色
       * 
       * 5. columnsTemplate:定义列模板,设置4列等宽分布
       *    - '1fr 1fr 1fr 1fr' 表示4列,每列占用相等的空间
       * 
       * 6. rowsGap:设置行间距
       * 7. columnsGap:设置列间距
       */
      Grid() {
        /**
         * 使用ArkUI的ForEach渲染函数遍历gridData数组
         * ForEach语法:ForEach(数据源, 项生成器, 键生成器)
         * 键生成器用于优化渲染性能,确保每个项有唯一标识
         */
        ForEach(
          this.gridData,
          (item: number, index: number) => {
            /**
             * GridItem:网格中的每个单元格
             * 设置高度、背景色、对齐方式等属性
             */
            GridItem() {
              /**
               * 每个网格项内部使用Column布局,显示序号和标签
               */
              Column() {
                /**
                 * 显示网格项序号
                 * 使用较大字体和粗体,突出显示
                 */
                Text(`${item}`)
                  .fontSize(24)
                  .fontWeight(FontWeight.Bold)
                  .margin({ bottom: 5 });

                /**
                 * 显示网格项标签
                 * 使用较小字体,辅助说明
                 */
                Text('网格项')
                  .fontSize(12)
                  .opacity(0.7);
              }
              /**
               * 设置网格项内部内容居中对齐
               */
              .justifyContent(FlexAlign.Center)
              .alignItems(HorizontalAlign.Center)
            }
            /**
             * 设置GridItem的高度
             * 使用100vp固定高度,使每个网格项大小一致
             */
            .height(100)
            /**
             * 根据索引计算背景色,实现斑马纹效果
             * 偶数索引使用浅蓝色,奇数索引使用浅灰色
             */
            .backgroundColor(index % 2 === 0 ? '#e3f2fd' : '#f5f5f5')
            /**
             * 设置圆角,使网格项边角圆润
             */
            .borderRadius(8);
          },
          (item: number) => `${item}`
        );
      }
      /**
       * 设置Grid容器固定高度为500vp
       * 这是实现滚动效果的关键:当内容高度超过500vp时,自动出现滚动条
       */
      .height(500)
      /**
       * 设置Grid宽度为100%,占满父容器宽度
       */
      .width('100%')
      /**
       * 设置网格列模板:4列等宽分布
       */
      .columnsTemplate('1fr 1fr 1fr 1fr')
      /**
       * 设置列间距为10vp
       */
      .columnsGap(10)
      /**
       * 设置行间距为10vp
       */
      .rowsGap(10)
      /**
       * 设置Grid内边距,使内容与边缘保持一定距离
       */
      .padding(10)
      /**
       * 设置滚动条显示状态,绑定到@State变量,支持动态切换
       */
      .scrollBar(this.currentBarState)
      /**
       * 设置滚动条宽度为8vp
       */
      .scrollBarWidth(8)
      /**
       * 设置滚动条滑块颜色,绑定到@State变量,支持动态切换
       */
      .scrollBarColor(this.barColors[this.currentColorIndex])
      /**
       * 设置Grid背景色为白色
       */
      .backgroundColor('#ffffff')
      /**
       * 设置Grid圆角,使整体外观更美观
       */
      .borderRadius(12)
      /**
       * 添加外边距,使Grid与其他元素保持距离
       */
      .margin({ top: 15 });

      /**
       * 底部说明区域
       * 展示布局要点和技术说明
       */
      Column() {
        Text('布局要点说明:')
          .fontSize(16)
          .fontWeight(FontWeight.Bold)
          .margin({ top: 15, bottom: 10 });

        Text('1. Grid组件必须设置固定高度(height属性)才能触发滚动')
          .fontSize(14)
          .margin({ bottom: 5 })
          .opacity(0.8);

        Text('2. scrollBar属性控制滚动条显示状态(Auto/On/Off)')
          .fontSize(14)
          .margin({ bottom: 5 })
          .opacity(0.8);

        Text('3. scrollBarWidth和scrollBarColor自定义滚动条样式')
          .fontSize(14)
          .margin({ bottom: 5 })
          .opacity(0.8);

        Text('4. columnsTemplate定义列布局,如"1fr 1fr 1fr 1fr"表示4列等宽')
          .fontSize(14)
          .opacity(0.8);

        Text('5. 使用ForEach渲染大量数据,键生成器确保渲染性能')
          .fontSize(14)
          .opacity(0.8);
      }
      /**
       * 设置底部说明区域的宽度和内边距
       */
      .width('100%')
      .padding({ left: 15, right: 15, bottom: 20 });
    }
    /**
     * 设置根Column容器占满整个屏幕
     */
    .height('100%')
    .width('100%')
    /**
     * 设置背景色为浅灰色,使页面更美观
     */
    .backgroundColor('#f5f5f5');
  }
}

五、Grid+scrollBar布局原理深度解析

5.1 滚动触发机制

Grid组件的滚动功能是基于容器尺寸和内容尺寸的比较实现的:

  1. 容器尺寸:由height属性决定,如.height(500)表示容器高度为500vp
  2. 内容尺寸:由GridItem的数量、高度和间距共同决定
  3. 滚动触发条件:当内容尺寸 > 容器尺寸时,自动启用滚动功能

内容高度计算公式:

内容高度 = (GridItem数量 / 列数) × (GridItem高度 + 行间距) + 内边距

示例计算:

GridItem数量 = 100
列数 = 4
GridItem高度 = 100vp
行间距 = 10vp
内边距 = 10vp

行数 = 100 / 4 = 25行
内容高度 = 25 × (100 + 10) + 20 = 2770vp

容器高度 = 500vp

滚动区域 = 2770vp - 500vp = 2270vp

5.2 滚动条渲染原理

滚动条的渲染涉及以下关键参数:

5.2.1 滑块高度计算

滑块高度与内容总量和容器尺寸相关:

滑块高度 = 容器高度 × (容器高度 / 内容高度)
5.2.2 滑块位置计算

滑块位置与当前滚动偏移量相关:

滑块位置 = 滚动偏移量 × ((容器高度 - 滑块高度) / (内容高度 - 容器高度))

5.3 BarState状态机制

5.3.1 BarState.Auto

在Auto模式下,滚动条的显示和隐藏由系统自动控制:

  • 显示时机:当用户开始滚动时,滚动条渐显
  • 隐藏时机:当用户停止滚动一段时间后(通常为1-2秒),滚动条渐隐
  • 实现原理:系统通过定时器监控滚动状态,在滚动停止后延迟隐藏
5.3.2 BarState.On

在On模式下,滚动条始终显示:

  • 适用场景:需要用户明确感知滚动区域的场景
  • 实现原理:滚动条的opacity始终为1,不随滚动状态变化
5.3.3 BarState.Off

在Off模式下,滚动条始终隐藏:

  • 适用场景:全屏沉浸式体验、自定义滚动指示器等场景
  • 实现原理:滚动条的opacity始终为0,或不渲染滚动条组件

六、API Level相关特性说明

6.1 API Level概述

API Level是HarmonyOS中用于标识API版本的数值,不同的API Level对应不同的系统版本和功能支持。开发者在使用API时,需要根据目标设备的API Level选择合适的API。

6.2 scrollBar相关API的API Level支持

属性/事件 API Level
scrollBar 8+
scrollBarColor 11+
scrollBarWidth 11+
scrollBarMargin 20+
onScrollStart 11+
onScrollStop 11+
onReachStart 11+
onReachEnd 11+
onDidScroll 12+

6.3 API Level 24兼容性说明

对于API Level 24的目标设备,上述所有scrollBar相关API均已支持。开发者可以放心使用以下特性:

  • scrollBar属性控制滚动条显示状态
  • scrollBarWidth设置滚动条宽度
  • scrollBarColor设置滚动条颜色
  • scrollBarMargin设置滚动条边距(仅支持top/bottom)
  • 所有滚动事件监听

6.4 scrollBarMargin属性详解

scrollBarMargin属性用于设置滚动条与组件边缘的距离,仅支持top和bottom两个方向:

Grid() {
  // GridItem子组件
}
.height(500)
.scrollBar(BarState.Auto)
.scrollBarMargin({ 
  top: 10, 
  bottom: 10 
})

注意:scrollBarMargin属性仅支持top和bottom方向的边距设置,不支持left和right方向。


七、常见问题与解决方案

7.1 滚动条不显示问题

问题描述:设置了scrollBar属性,但滚动条不显示

可能原因及解决方案

原因 解决方案
Grid未设置固定高度 设置.height(500)等固定高度
内容高度未超过容器高度 增加GridItem数量或高度
scrollBar设置为BarState.Off 修改为BarState.Auto或BarState.On

调试代码示例

Grid() {
  ForEach(this.gridData, (item) => {
    GridItem() {
      Text(`${item}`)
    }
    .height(100);
  }, (item) => `${item}`);
}
.height(500) // 必须设置固定高度
.scrollBar(BarState.Auto) // 使用Auto或On状态

7.2 滚动条样式不生效问题

问题描述:设置了scrollBarWidth和scrollBarColor,但样式不生效

可能原因及解决方案

原因 解决方案
API Level版本过低 确保API Level >= 11
属性顺序错误 scrollBar样式属性应在scrollBar属性之后设置
颜色值格式错误 使用正确的颜色格式,如’#2196f3’或Color.Blue

正确代码示例

Grid() {
  // GridItem子组件
}
.height(500)
.scrollBar(BarState.Auto) // 先设置滚动条状态
.scrollBarWidth(8) // 再设置宽度
.scrollBarColor('#2196f3') // 最后设置颜色

7.3 ForEach渲染性能问题

问题描述:大量数据渲染时出现卡顿

解决方案

  1. 使用键生成器:确保ForEach的第三个参数(键生成器)返回唯一值
  2. 控制数据量:通过分页加载等方式控制单次渲染的数据量
  3. 优化GridItem:减少GridItem内部的嵌套层级和复杂组件

优化代码示例

Grid() {
  ForEach(
    this.gridData,
    (item: number) => {
      GridItem() {
        // 简化GridItem内容
        Text(`${item}`)
          .fontSize(24);
      }
      .height(100);
    },
    (item: number) => `${item}` // 键生成器返回唯一值
  );
}
.height(500)
.scrollBar(BarState.Auto);

7.4 滚动事件不触发问题

问题描述:设置了onScrollStart、onScrollStop等事件,但不触发

解决方案

  1. 确认API Level:确保API Level >= 11
  2. 确认滚动触发条件:内容高度必须超过容器高度
  3. 检查事件语法:确保事件回调函数语法正确

正确代码示例

Grid() {
  // GridItem子组件
}
.height(500)
.onScrollStart(() => {
  console.info('滚动开始');
})
.onScrollStop(() => {
  console.info('滚动停止');
});

7.5 箭头函数参数类型标注问题

问题描述:在ForEach或事件回调中使用箭头函数参数类型标注时报错

解决方案:ArkTS支持在箭头函数参数中使用类型标注,但需要注意语法正确性:

// 正确用法
ForEach(
  this.gridData,
  (item: number, index: number) => {
    // 正确的类型标注方式
  },
  (item: number) => `${item}`
);

// 事件回调
.onClick(() => {
  // 无参数时不需要类型标注
});

7.6 Array.from不支持问题

问题描述:使用Array.from创建数组时报错

解决方案:ArkTS不支持Array.from方法,需要手动创建数组:

// 错误用法
@State gridData: number[] = Array.from({ length: 100 }, (_, i) => i + 1);

// 正确用法
private createGridData(): number[] {
  let data: number[] = [];
  for (let i = 0; i < 100; i++) {
    data.push(i + 1);
  }
  return data;
}

@State gridData: number[] = this.createGridData();

7.7 textAlign字符串参数问题

问题描述:使用textAlign(‘center’)时报错

解决方案:textAlign属性需要使用TextAlign枚举值:

// 错误用法
.textAlign('center')

// 正确用法
.textAlign(TextAlign.Center)

7.8 Column组件alignItems属性问题

问题描述:使用Column组件的alignItems(FlexAlign.Center)时报错

解决方案:Column组件的alignItems属性需要使用HorizontalAlign枚举:

// 错误用法
Column() {
  // 内容
}
.alignItems(FlexAlign.Center);

// 正确用法
Column() {
  // 内容
}
.alignItems(HorizontalAlign.Center);

对齐枚举总结

  • Column组件:justifyContent使用FlexAlign,alignItems使用HorizontalAlign
  • Row组件:justifyContent使用FlexAlign,alignItems使用VerticalAlign

八、性能优化策略

8.1 虚拟滚动优化

Grid组件内置虚拟滚动机制,只渲染可见区域的GridItem,显著提升性能。

虚拟滚动工作原理

  1. 计算可见区域:根据容器尺寸和滚动位置,计算当前可见的GridItem范围
  2. 渲染可见项:只渲染可见范围内的GridItem
  3. 复用组件:当GridItem滚出可见区域时,回收组件资源;当新的GridItem滚入时,复用已回收的组件

虚拟滚动配置

Grid() {
  ForEach(
    this.gridData,
    (item) => {
      GridItem() {
        // GridItem内容
      }
    },
    (item) => `${item}`
  );
}
.height(500)
// 虚拟滚动默认启用,无需额外配置

8.2 数据加载优化

分页加载

@State gridData: number[] = [];
@State pageIndex: number = 1;
private pageSize: number = 20;

private loadMoreData(): void {
  let newData: number[] = [];
  let startIndex = (this.pageIndex - 1) * this.pageSize;
  for (let i = startIndex; i < startIndex + this.pageSize; i++) {
    newData.push(i + 1);
  }
  this.gridData = this.gridData.concat(newData);
  this.pageIndex++;
}

build() {
  Grid() {
    ForEach(
      this.gridData,
      (item) => {
        GridItem() {
          Text(`${item}`)
        }
        .height(100);
      },
      (item) => `${item}`
    );
  }
  .height(500)
  .scrollBar(BarState.Auto)
  .onReachEnd(() => {
    // 滚动到底部时加载更多数据
    this.loadMoreData();
  });
}

8.3 GridItem优化

减少嵌套层级

// 优化前:多层嵌套
GridItem() {
  Column() {
    Row() {
      Text('内容')
    }
  }
}

// 优化后:减少嵌套
GridItem() {
  Text('内容')
}

使用@Builder提取公共组件

@Builder
GridItemBuilder(item: number) {
  Text(`${item}`)
    .fontSize(24)
    .fontWeight(FontWeight.Bold);
}

build() {
  Grid() {
    ForEach(
      this.gridData,
      (item) => {
        GridItem() {
          this.GridItemBuilder(item);
        }
        .height(100);
      },
      (item) => `${item}`
    );
  }
  .height(500);
}

8.4 样式优化

避免频繁的样式计算

// 优化前:每次渲染都计算颜色
.backgroundColor(index % 2 === 0 ? '#e3f2fd' : '#f5f5f5')

// 优化后:使用预定义的颜色数组
private colors: string[] = ['#e3f2fd', '#f5f5f5'];
.backgroundColor(this.colors[index % 2])

九、实战案例:图片画廊应用

9.1 案例概述

本案例实现一个图片画廊应用,展示如何使用Grid+scrollBar布局实现图片网格展示和滚动功能。

9.2 功能需求

  1. 展示图片的网格布局
  2. 支持滚动浏览
  3. 显示滚动条
  4. 支持图片点击查看详情

9.3 代码实现

@Entry
@Component
struct PhotoGallery {
  @State photos: string[] = this.createPhotoData();
  @State selectedPhoto: string = '';

  private createPhotoData(): string[] {
    let data: string[] = [];
    for (let i = 1; i <= 30; i++) {
      data.push(`photo_${i}`);
    }
    return data;
  }

  private onPhotoClick(photo: string): void {
    this.selectedPhoto = photo;
    // 可以在这里打开详情页面或对话框
    console.info(`点击了图片: ${photo}`);
  }

  build() {
    Column() {
      Text('图片画廊')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .padding({ top: 20, bottom: 15 })
        .width('100%')
        .textAlign(TextAlign.Center)
        .backgroundColor('#f0f0f0');

      Grid() {
        ForEach(
          this.photos,
          (photo: string, index: number) => {
            GridItem() {
              Column() {
                Text(photo)
                  .fontSize(16)
                  .fontWeight(FontWeight.Medium);
                
                Text(`${index + 1}`)
                  .fontSize(12)
                  .opacity(0.7);
              }
              .justifyContent(FlexAlign.Center)
              .alignItems(HorizontalAlign.Center)
              .width('100%')
              .height(120)
              .backgroundColor(index % 2 === 0 ? '#e3f2fd' : '#fff3e0')
              .borderRadius(8)
              .onClick(() => {
                this.onPhotoClick(photo);
              });
            }
          },
          (photo: string) => photo
        );
      }
      .height('100%')
      .width('100%')
      .columnsTemplate('1fr 1fr 1fr')
      .columnsGap(10)
      .rowsGap(10)
      .padding(10)
      .scrollBar(BarState.Auto)
      .scrollBarWidth(6)
      .scrollBarColor('#2196f3');
    }
    .height('100%')
    .width('100%')
    .backgroundColor('#f5f5f5');
  }
}

十、总结与展望

10.1 核心要点总结

Grid组件:

  • 用于实现网格布局的核心容器组件
  • 需要设置固定高度才能触发滚动
  • 支持自定义列数、行高、间距等属性

scrollBar属性:

  • 控制滚动条的显示状态(Auto/On/Off)
  • scrollBarWidth设置滚动条宽度(API Level 11+)
  • scrollBarColor设置滚动条颜色(API Level 11+)
  • scrollBarMargin设置滚动条边距(API Level 20+,仅支持top/bottom)
  • 支持多种滚动事件监听(API Level 11+)

布局要点:

  • Grid容器必须设置固定高度
  • 内容高度超过容器高度时自动触发滚动
  • 使用ForEach渲染大量数据时必须提供键生成器
  • Column组件的alignItems使用HorizontalAlign枚举
  • Row组件的alignItems使用VerticalAlign枚举

ArkTS语法注意事项:

  • 不支持Array.from,需要手动创建数组
  • textAlign属性需要使用TextAlign枚举值
  • 箭头函数参数可以使用类型标注

10.2 未来发展趋势

随着HarmonyOS NEXT的不断发展,Grid+scrollBar布局将迎来更多优化:

  1. 性能提升:虚拟滚动机制将更加高效,支持更大数据量
  2. 样式定制:滚动条样式将支持更多自定义选项
  3. 交互增强:支持更多滚动手势和交互方式
  4. 响应式布局:Grid组件将更好地支持多设备适配

10.3 学习建议

  1. 深入理解布局原理:掌握Grid组件的布局计算和滚动触发机制
  2. 实践API使用:通过实际项目练习scrollBar相关属性的使用
  3. 关注性能优化:学习虚拟滚动和数据加载优化技巧
  4. 参考官方文档:定期查阅HarmonyOS官方文档,了解最新API特性

附录:API参考

Grid组件属性

属性名 类型 说明 API Level
columnsTemplate string 列模板定义 8+
columnsGap number 列间距 8+
rowsGap number 行间距 8+
rowHeight Length 行高度 8+
height Length 容器高度 8+
width Length 容器宽度 8+

scrollBar相关属性

属性名 类型 说明 API Level
scrollBar BarState 滚动条显示状态 8+
scrollBarWidth number 滚动条宽度 11+
scrollBarColor ResourceColor 滚动条颜色 11+
scrollBarMargin EdgeInsets 滚动条边距(仅支持top/bottom) 20+

滚动事件

事件名 说明 API Level
onScrollStart 滚动开始时触发 11+
onScrollStop 滚动停止时触发 11+
onReachStart 滚动到起始位置时触发 11+
onReachEnd 滚动到末尾位置时触发 11+
onDidScroll 滚动过程中触发 12+

BarState枚举

枚举值 说明
BarState.Auto 自动显示/隐藏
BarState.On 始终显示
BarState.Off 始终隐藏

TextAlign枚举

枚举值 说明
TextAlign.Center 居中对齐
TextAlign.Start 起始对齐
TextAlign.End 末尾对齐

HorizontalAlign枚举

枚举值 说明
HorizontalAlign.Center 水平居中
HorizontalAlign.Start 水平起始
HorizontalAlign.End 水平末尾

VerticalAlign枚举

枚举值 说明
VerticalAlign.Center 垂直居中
VerticalAlign.Top 垂直顶部
VerticalAlign.Bottom 垂直底部

FlexAlign枚举

枚举值 说明
FlexAlign.Center 居中
FlexAlign.Start 起始
FlexAlign.End 末尾
FlexAlign.SpaceBetween 两端对齐
FlexAlign.SpaceAround 均匀分布
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐