鸿蒙grid-hybrid项目UI滚动联动

grid-hybrid项目 gitee.com/harmonyos_s...

此项目交互场景相对复杂,可作为实际应用交互场景的草稿,进一步完善。譬如百度文库的UI交互。

一、GridNestListIndex页面交互

-- 多种控件的Scroller滚动联动

项目中GridNestListIndex 页面通过以下方式实现了滚动联动效果:


1. 核心组件与状态

  • Scroll 组件:用于页面的整体滚动。
  • List 组件:用于展示网格项列表。
  • Scroller 对象
    • scrollerForScroll:控制页面整体滚动。
    • scrollerForList:控制列表滚动。
    • scrollerForTitle:控制标题栏的横向滚动。
  • 状态变量
    • listPosition:记录列表的滚动位置(顶部、中间、底部)。
    • scrollPosition:记录页面的滚动位置(顶部、中间、底部)。
    • currentIndex:记录当前显示的列表项的索引。

2. 滚动联动实现逻辑

(1) 列表滚动触发标题栏联动

  • onScrollIndex 事件
    • 当列表滚动时,通过 onScrollIndex 获取当前显示的第一个子组件的索引 start
    • 更新 currentIndex 状态,并调用 scrollerForTitle.scrollToIndex 同步标题栏的滚动位置。

(2) 标题栏点击触发列表联动

  • 标题栏点击事件
    • 点击标题栏时,调用 scrollerForList.scrollToIndex 滚动列表到对应索引。
    • 同时调用 scrollerForScroll.scrollEdge(Edge.Bottom) 确保页面滚动到底部(避免标题栏遮挡列表)。
    • 更新 currentIndex 状态。

(3) 页面滚动与列表滚动联动

  • onScrollFrameBegin 事件
    • 当列表滚动时,通过 onScrollFrameBegin 计算偏移量 offset
    • 如果页面已滚动到底部(scrollPosition === ScrollPosition.end),且列表不在顶部或向上滚动,则允许列表继续滚动。
    • 否则,通过 scrollerForScroll.scrollBy 同步页面的滚动。

(4) 页面滚动状态同步

  • onWillScrollonScrollEdge 事件
    • 监听页面滚动方向,更新 scrollPosition 状态(顶部、中间、底部)。
    • 当页面滚动到顶部或底部时,禁止进一步滚动(通过 onScrollFrameBegin 返回 offsetRemain: 0)。

3. 关键代码片段

  • 列表滚动索引同步

    typescript 复制代码
    .onScrollIndex((start: number) => {
      this.currentIndex = start;
      this.scrollerForTitle.scrollToIndex(this.currentIndex);
    })
  • 标题栏点击联动

    typescript 复制代码
    .onClick(() => {
      this.scrollerForList.scrollToIndex(index);
      this.scrollerForScroll.scrollEdge(Edge.Bottom);
      this.scrollerForTitle.scrollToIndex(index);
      this.currentIndex = index;
    })
  • 页面与列表滚动同步

    typescript 复制代码
    .onScrollFrameBegin((offset: number) => {
      if (this.scrollPosition === ScrollPosition.end && (this.listPosition != ScrollPosition.start || offset > 0)) {
        return { offsetRemain: offset };
      } else {
        this.scrollerForScroll.scrollBy(0, offset);
        return { offsetRemain: offset };
      }
    })

4. 总结

通过 Scroller 对象和状态变量的协同工作,GridNestListIndex 实现了以下联动效果:

  1. 列表滚动时,标题栏自动同步到对应位置。
  2. 点击标题栏时,列表滚动到对应项,并确保页面布局正确。
  3. 页面滚动时,动态调整列表的滚动行为,避免冲突。

这种设计确保了用户体验的流畅性和一致性。

-- Grid的样式设置

GridComponent.ets 文件中,Grid 组件的行列数、宽高和布局是通过以下方式控制的:


1. 行列数控制

(1) 列数控制

  • columnsTemplate 属性
    • 通过 CommonConstants.GRID_COLUMNS_TEMPLATE 定义列模板。
    • 例如:'1fr 1fr 1fr 1fr' 表示 4 列,每列宽度均分剩余空间。

(2) 行数动态计算

  • 动态计算
    • 行数由 gridData.gridItemList.length 和列数决定。
    • 例如:Math.ceil(this.gridData.gridItemList.length / 4) 表示每行 4 个项,计算总行数。

2. 宽高控制

(1) 宽度

  • width 属性
    • 默认继承父容器宽度(CommonConstants.FULL_PERCENT)。

    • 可通过 margin 调整左右边距:

      typescript 复制代码
      .margin({
        left: $r('app.float.grid_left_margin'),
        right: $r('app.float.grid_right_margin')
      })

(2) 高度

  • height 属性
    • 通过 getGridHeight() 方法动态计算:

      typescript 复制代码
      .height(this.getGridHeight())
    • 计算逻辑

      • 每行高度固定为 68(网格项高度)。

      • 行间距为 8

      • 上下边距为 12 * 2

      • 公式:

        typescript 复制代码
        gridHeight += Math.ceil(this.gridData.gridItemList.length / 4) * 68; // 行高
        gridHeight += (Math.ceil(this.gridData.gridItemList.length / 4) - 1) * 8; // 行间距
        gridHeight += 12 * 2; // 上下边距

3. 间距与对齐

(1) 行间距

  • rowsGap 属性
    • 通过 $r('app.float.grid_rows_gap_size') 设置行间距。

(2) 内边距

  • padding 属性
    • 通过 $r('app.float.grid_padding_size') 设置内边距。

(3) 圆角

  • borderRadius 属性
    • 通过 $r('app.float.grid_border_radius') 设置圆角。

4. 关键代码片段

typescript 复制代码
Grid() {
  ForEach(this.gridData.gridItemList, (item: string) => {
    GridItemComponent({ itemName: item })
  })
}
.columnsTemplate(CommonConstants.GRID_COLUMNS_TEMPLATE) // 列模板
.margin({ left: $r('app.float.grid_left_margin'), right: $r('app.float.grid_right_margin') }) // 左右边距
.height(this.getGridHeight()) // 动态高度
.rowsGap($r('app.float.grid_rows_gap_size')) // 行间距
.padding($r('app.float.grid_padding_size')) // 内边距
.borderRadius($r('app.float.grid_border_radius')) // 圆角

5. 总结

  • 列数 :由 columnsTemplate 定义(如 4 列)。
  • 行数:动态计算(根据数据项数和列数)。
  • 宽度 :继承父容器,通过 margin 调整边距。
  • 高度:动态计算(行高 + 行间距 + 边距)。
  • 间距与样式 :通过 rowsGappadding 等属性控制。

这种设计确保了网格布局的灵活性和响应性。

二、GridNestSwiperIndex页面交互

GridNestSwiperIndex.ets 文件中,页面通过 SwiperWaterFlow 组件的协同工作,实现了一个动态的混合布局效果。以下是页面的完整解析:


1. 页面结构与功能

(1) 整体布局

  • 顶层容器Column 纵向排列,包含 Swiper(顶部滑动菜单)和 WaterFlow(下方瀑布流内容)。
  • 交互逻辑
    • Swiper 切换分类时,动态调整自身高度,间接影响 WaterFlow 的展示空间。
    • WaterFlow 根据数据源和分区配置,动态渲染内容项。

(2) 核心组件

组件 作用 数据依赖 动态控制点
Swiper 横向滑动菜单 GRID_COL_LIST swiperDistance(高度)
WaterFlow 瀑布流内容展示 WATER_FLOW_DATA sections(分区配置)

2. 数据驱动设计

(1) Swiper 分页与高度

  • 分页数据
    GRID_COL_LIST 定义分页内容和数量,例如:

    typescript 复制代码
    GRID_COL_LIST = [
      ["推荐", "热门"], // 第一页
      ["最新", "分类"]  // 第二页
    ]
  • 高度控制
    通过滑动事件 (onGestureSwipe) 和动画回调 (onAnimationStart) 动态设置 swiperDistance

    typescript 复制代码
    .onGestureSwipe((index: number) => {
      this.swiperDistance = (index === 0) ? SWIPER_HEIGHT_SIZE2 : SWIPER_HEIGHT_SIZE1;
    })

(2) WaterFlow 分区与内容

  • 数据源
    WATER_FLOW_DATA 提供内容项数据(如图片资源),通过 WaterFlowDataSource 封装。

  • 分区配置
    sections 定义布局规则,例如:

    typescript 复制代码
    sections = [
      { itemsCount: 1, crossCount: 1 }, // 单栏Banner
      { itemsCount: 6, crossCount: 2 }  // 双栏商品列表
    ]
  • 动态渲染
    使用 LazyForEach 按需生成 FlowItem

    typescript 复制代码
    LazyForEach(this.waterFlowDataSource, (item: Resource) => {
      FlowItem() {
        Image(item) // 绑定数据
      }
    })

3. 关键交互流程

  1. 初始化

    • 加载 GRID_COL_LISTWATER_FLOW_DATA
    • 配置 sections 分区。
  2. 用户滑动 Swiper

    • 触发 onGestureSwipe → 更新 swiperDistance
    • 动画过渡高度变化。
  3. WaterFlow 响应

    • 高度变化后,layoutWeight(1) 自动调整内容区域空间。
    • 根据当前分区重新布局项。

4. 设计优势与扩展性

(1) 优势

  • 性能优化LazyForEach 懒加载 + 动画平滑过渡。
  • 灵活配置 :通过修改 sections 或数据源即可调整布局。

(2) 扩展建议

  • 动态数据 :通过接口异步更新 GRID_COL_LISTWATER_FLOW_DATA
  • 高度自适应 :根据 WaterFlow 内容高度动态计算 swiperDistance

如果需要进一步调整或扩展功能,请具体说明需求!

相关推荐
nashane6 小时前
HarmonyOS 6学习:CapsLock键失效诊断与长截图完整实现指南
学习·华为·harmonyos
richard_yuu8 小时前
鸿蒙心理测评模块实战|PHQ-9/GAD7双量表答题、实时计分与结果本地化存储
华为·harmonyos
不爱吃糖的程序媛11 小时前
2026年Electron 鸿蒙PC环境搭建指南
人工智能·华为·harmonyos
nashane11 小时前
HarmonyOS 6学习:长截图功能开发中的滚动拼接与权限处理实战
人工智能·华为·harmonyos
大师兄666812 小时前
从零开发一个 HarmonyOS 输入法——KikaInputMethod 完整拆解
harmonyos·服务卡片·harmonyos6·formkit
Python私教18 小时前
鸿蒙 NEXT 也能接 MCP?用 ArkTS 跑通 AI Agent 工具链
人工智能·华为·harmonyos
Swift社区20 小时前
分布式能力在鸿蒙 PC 上到底怎么用?
分布式·华为·harmonyos
nashane1 天前
HarmonyOS 6学习:外接键盘CapsLock与长截图功能的实战调试与完整解决方案
学习·华为·计算机外设·harmonyos
aqi002 天前
一文理清 HarmonyOS 6.0.2 涵盖的十个升级点
android·华为·harmonyos·鸿蒙·harmony