当前位置: 首页 > news >正文

HarmonyOS7 列表流实战-----分组列表吸顶原来就这几步

文章目录

      • 源码获取
      • 吸顶这件事,难点不在动画,而在分组
      • 真正的前提不是 `sticky`,而是 `ListItemGroup`
      • 标题头为什么最好单独抽出来
      • 真正让标题吸住顶部的,就这一行
      • 如果只看一个页面来练,我更推荐 `CityList`
      • 你自己复刻时,最少得满足这三个条件
      • 有个细节很多人真会省,但我建议别省
      • 这种结构以后能直接套到哪类页面
      • 我最想提醒小白的三个误区
        • 误区一: 以为吸顶一定要自己算滚动距离
        • 误区二: 把标题直接塞进 `ListItem`
        • 误区三: 标题区样式写得太敷衍
      • 给你一个非常适合练手的小作业
      • 最后一句

源码获取

如果你想一边对照文章一边实操,建议直接把示例工程拉到本地。项目 Git 地址:https://gitcode.com/HarmonyOS_Samples/CommonListFlows

第一次看到“分组标题吸顶”的页面,很多人会本能地觉得这玩意儿很高级。

然后脑子里立刻开始脑补: 要不要监听滚动距离,要不要自己算偏移,要不要动态改定位。结果还没写代码,人已经先把自己吓着了。

说实话,这种担心大多是想多了。

在 ArkUI 的List体系里,分组吸顶真正关键的不是你会不会手搓动画,而是你有没有把列表结构组织对。这个项目里的HomePageCityList,刚好把这件事讲得很明白。

吸顶这件事,难点不在动画,而在分组

先把概念掰直。

所谓分组吸顶,就是你往下滑的时候,当前分组标题固定在顶部,等下一个分组上来,再把它顶走。

这种交互非常常见:

  • 城市选择页
  • 通讯录
  • 分类商品列表
  • 按日期分组的消息页

所以你现在学的不是一个花哨技巧,而是一类特别高频的页面基础能力。

真正的前提不是sticky,而是ListItemGroup

先看HomePage里景区分组的写法:

ForEach(this.scenicSpotTitle,(item:Resource)=>{ListItemGroup({header:this.scenicSpotHeader(item)}){ForEach(this.scenicSpotArray,(scenicSpotItem:Resource)=>{ListItem(){this.scenicSpotDetailBuilder(scenicSpotItem)}},(scenicSpotItem:Resource)=>JSON.stringify(scenicSpotItem))}},(item:Resource)=>JSON.stringify(item))

这段代码最值得记住的不是遍历细节,而是结构关系:

  • 外层按分类分组
  • 每一组都用ListItemGroup
  • 组里面再放具体ListItem

这一步才是吸顶真正的地基。

因为框架只有先知道“这是一组内容,这是一组的头部”,后面才有可能帮你做吸顶。你如果连分组关系都没建立,光盯着吸顶效果本身,基本是在白忙活。

标题头为什么最好单独抽出来

项目把分组头专门写成了一个Builder:

@BuilderscenicSpotHeader(title:Resource){Column(){Text(title).width('100%').height(50).fontSize(18).fontWeight(FontWeight.Bold).backgroundColor(0xF1F3F5)}}

这一步很实用。

因为分组标题通常不是只出现一次。你今天想改高度,明天想改背景色,后天又想加图标或者间距,如果一开始就散落在各处,后面会改得很烦。

抽出来以后,结构更清楚,维护也轻松。

真正让标题吸住顶部的,就这一行

很多人以为要写很长的滚动逻辑,其实项目里真正生效的是这句:

.sticky(StickyStyle.Header)

它直接挂在List上:

List({space:12}){// 列表内容}.sticky(StickyStyle.Header)

说白了,ArkUI 已经把常见分组吸顶能力准备好了。你要做的不是重新发明一遍,而是把它需要的结构喂对。

所以这里的正确心态应该是:

  • 先把分组关系建好
  • 再把分组头定义清楚
  • 最后让List开启sticky

顺序别反。

如果只看一个页面来练,我更推荐CityList

HomePage里的分组吸顶是入门版,CityList则更像标准模板。

它的核心结构是这样的:

List({scroller:this.cityScroller}){ListItemGroup({header:this.itemHead($r('app.string.current_city'))}){ListItem(){Text(this.currentCity)}}ListItemGroup({header:this.itemHead($r('app.string.popular_cities'))}){ForEach(this.hotCities,(item:string)=>{ListItem(){this.textContent(item)}})}ForEach(this.groupWorldList,(item:string)=>{ListItemGroup({header:this.itemHead(item)}){ForEach(this.getCitiesWithGroupName(item),(cityItem:City)=>{ListItem(){this.textContent(cityItem.city)}})}})}.sticky(StickyStyle.Header)

这页为什么特别适合拿来练?

因为结构太典型了:

  • 上面是特殊分组,比如当前城市、热门城市
  • 下面是按字母切开的标准分组
  • 所有内容都统一放进ListItemGroup
  • 吸顶逻辑完全交给sticky

这是一种特别干净的示范。

你自己复刻时,最少得满足这三个条件

如果你准备照着做一个类似页面,至少要保证这三点同时成立:

  • 外层容器是List
  • 每一组内容都用ListItemGroup
  • 组头通过header提供,并在列表上开启.sticky(StickyStyle.Header)

少任何一个,效果都不会完整。

别在这一步偷懒。

有个细节很多人真会省,但我建议别省

那就是分组头的背景色。

你可能会觉得,标题都显示出来了,背景色有没有都差不多。真不是。

分组头一旦吸到顶部,它其实是在内容上方“悬着”的。背景如果不明确,下面列表内容会透出来,页面看着立刻廉价很多。这个项目里不管是景区标题还是城市标题,都专门给了背景色,这不是装饰,是经验。

这种结构以后能直接套到哪类页面

别把它只当城市页技巧。

这一套你以后完全可以原样迁过去:

  • 城市选择页按字母分组
  • 订单页按日期分组
  • 消息中心按类型分组
  • 商品列表按品类分组
  • 文档中心按月份分组

它们本质一样,都是“同类内容归一组,组头负责提示,滚动时让组头持续在线”。

我最想提醒小白的三个误区

误区一: 以为吸顶一定要自己算滚动距离

普通分组吸顶真不用。先把结构写对,再谈更复杂的动画需求。

误区二: 把标题直接塞进ListItem

视觉上看着像有标题,但框架并不知道它是“组头”,自然也不会帮你吸顶。

误区三: 标题区样式写得太敷衍

高度、背景、间距全乱来,最后吸顶动作虽然发生了,页面质感却很差。

给你一个非常适合练手的小作业

你可以在CityList上先做两件小事:

  • 给字母标题提一点对比度,比如更粗的字重或者更明确的背景
  • 给城市项加分割线或者卡片样式

这两个改动不会碰核心逻辑,但能让你很直接地感受到: 列表结构没变,页面气质却能差很多。

最后一句

分组吸顶这件事,真正难的从来不是 API,而是你有没有先把“分组”这件事想清楚。

一旦你接受“组用ListItemGroup管,吸顶交给sticky”这套思路,很多原本看起来像高阶页面的东西会突然变简单。别自己先把它想复杂了,框架其实已经替你省了不少力气。

http://www.jsqmd.com/news/1075986/

相关文章:

  • 中科蓝讯-测试耳机本地手机铃声
  • AI视觉+软件,正在重构餐饮后厨与前厅的数据闭环
  • Wayback Machine浏览器扩展终极指南:一键保存与恢复消失网页的完整教程
  • 性能测评|2026年电动平车十大厂家排行榜TOP10
  • 用GPT-4极简提示词生成Streamlit交互地图
  • Path of Building PoE2:免费开源的流放之路2角色构建终极指南
  • CSRF攻击原理、防御与实战:从漏洞复现到Token安全实践
  • TDengine STMT 参数绑定 — 高性能批量写入与查询的最佳方式
  • 鸿蒙 ArkUI 基础表单与卡片组件实训博客
  • Tacent View:游戏纹理与专业图像处理的现代化解决方案
  • Topit:让你的Mac窗口永远在最前方,工作效率提升300%的秘密武器
  • 生产级机器学习服务落地:ONNX+Triton实战指南
  • 决策树实战:用可解释规则简化复杂业务选择
  • GitHub Desktop中文汉化完整指南:5分钟告别英文困扰
  • 2026保姆级Word文档压缩大小教程,图文图片压缩、清理隐藏数据、另存压缩全方法
  • TestDisk PhotoRec:免费开源的数据恢复终极解决方案
  • 澳大利亚海牙认证在哪里办理?澳洲海牙认证办理流程是什么?
  • GEO 贴牌怎么做 2026 选型攻略,依托实测案例规避贴牌套路
  • HarmonyOS7 列表流实战 ----别急着改代码,先把示例工程真正跑通
  • Beyond Compare 5密钥生成完整指南:从逆向分析到激活实战
  • o3-mini驱动的端到端ML工程化实战:从推理协同到低摩擦部署
  • 墨香润夏:临汾夏令营里的文脉与成长
  • TriliumNext × WechatSync Publisher Bridge 同时同步多篇文章
  • Hadoop练习卷大题部分简洁答案
  • OpCore Simplify:三步实现专业级黑苹果EFI配置
  • AI赋能传统行业:从生产到营销的生存重构与收藏指南
  • 2026前端开发新范式:用Gemini镜像站解决React/Vue组件设计、状态管理与性能瓶颈
  • 如何将iPhone照片备份到电脑/iCloud/iTunes
  • 面试官:为什么你的GEO内容“看起来正常但就是不被引用”?我用一套日志系统抓到了真凶
  • MuleSoft企业级AI编排实战:LLM与ERP/CRM安全集成