鸿蒙原生应用实战活动相册活动页的进行中/已结束卡片列表App 40「校园活动照片」活动页Func1Tab主题色#6C5CE7紫色violet4 个 Tab 分别为首页、活动、上传、我的。活动页采用Header 分段切换 活动列表三区布局——白色双行 Header活动20 号加粗 进行中 / 已结束两段切换State tab 驱动选中态4 张活动卡片 2026 迎新晚会 / 秋季运动会 / 校园音乐节 / 话剧社公演每张含 120 高 emoji 大图区 活动名 日期 参与人数 照片数 紫色查看相册 。本篇基于40-event-photo/entry/src/main/ets/pages/Func1Tab.ets共 89 行逐段拆解附 4 张实机截图。一、整体结构三区Header 分段 活动列表布局活动页是品牌头部 状态分段 活动明细的三区布局build() { Column() { this.Header() Scroll() { Column({ space: 14 }) { this.EventList() } .width(100%) .padding({ left: D.pad, right: D.pad, top: 14, bottom: D.pad this.safeBottom 20 }) } .layoutWeight(1).scrollBar(BarState.Off).align(Alignment.Top) } .width(100%).height(100%).backgroundColor(C.bg) }3 块结构Header— 双行结构标题行 分段切换行都固定在顶部非滚动区Scroll— 活动卡片列表滚动区EventList— 4 张活动卡当前 Demo 两段共用同一列表切换只改变高亮态与首页同构的Header Scroll Column(space:14)骨架再次出现系列统一性延续。项目源码开源https://gitee.com/codenestFlow/HarmonyOSHub二、Header双行结构 分段切换Header() { Column() { Row() { Text(活动).fontSize(20).fontWeight(FontWeight.Bold).fontColor(C.text) } .width(100%).height(this.safeTop 52).padding({ top: this.safeTop, left: D.pad, right: D.pad }) .alignItems(VerticalAlign.Bottom) Row() { ForEach(this.tabs, (t: string, idx: number) { Text(t).fontSize(14) .fontColor(this.tab idx ? C.primary : C.textSub) .fontWeight(this.tab idx ? FontWeight.Bold : FontWeight.Normal) .layoutWeight(1).textAlign(TextAlign.Center).padding({ bottom: 12 }) .onClick(() { this.tab idx; }) }, (t: string) t) }.width(100%) }.width(100%).backgroundColor(C.card) }技术拆解标题行活动20 号加粗safeTop 52高度、文字底部对齐——与系列其他二级页一致。分段切换行ForEach(this.tabs, ...)遍历[进行中, 已结束]两个字符串每个 Text 用layoutWeight(1)平分整行宽度、textAlign(TextAlign.Center)居中。选中态驱动State tab: number记录当前选中索引this.tab idx决定颜色选中紫色加粗 / 未选灰色常规——这是文本模拟分段控件的经典实现比Tabs/TabContent轻量得多适合只有两三个分段的场景。点击切换onClick(() { this.tab idx; })更新索引UI 自动重绘。底部内边距padding({ bottom: 12 })让分段文字与下方滚动内容保持间距。分段交互的意义产品语义上进行中展示正在举办的活动、已结束展示历史活动可回顾照片。Demo 为演示简洁共用同一列表真实实现中tab 0时渲染进行中数据源、tab 1时渲染已结束数据源即可切换逻辑已就绪。三、EventList活动卡片列表EventList() { Column({ space: 14 }) { ForEach(this.events, (e: Event) { Column() { Row() { Text(e.emoji).fontSize(50) } .width(100%).height(120).backgroundColor(C.primarySoft) .borderRadius({ topLeft: D.rLg, topRight: D.rLg }).justifyContent(FlexAlign.Center) Column({ space: 8 }) { Text(e.name).fontSize(16).fontWeight(FontWeight.Bold).fontColor(C.text).width(100%) Row() { Text( e.date).fontSize(12).fontColor(C.textDim).layoutWeight(1) Text( e.joined 人参与).fontSize(12).fontColor(C.textDim) }.width(100%) Row() { Text( e.photos 张照片).fontSize(12).fontColor(C.primary).layoutWeight(1) Text(查看相册 ).fontSize(12).fontColor(C.primary) }.width(100%) }.padding(14) } .width(100%).backgroundColor(C.card).borderRadius(D.rLg).border({ width: 1, color: C.stroke }) .onClick(() { promptAction.showToast({ message: e.name }); }) }, (e: Event) e.id.toString()) }.width(100%) }活动数据23-28 行由private events: Event[]静态数组提供活动日期参与人数照片数 2026 迎新晚会9月10日320128 秋季运动会10月15日580256 校园音乐节11月2日450176 话剧社公演11月20日12045卡片细节大图区120 高、50 号 emoji 居中、primarySoft浅紫底、只圆上两角borderRadius({ topLeft: D.rLg, topRight: D.rLg })——比首页瀑布流卡46 号 emoji、140~200 高更大更醒目活动卡是主推对象。活动名16 号加粗全宽信息层级最高。元信息第一行 日期与 N 人参与用RowlayoutWeight(1)分列左右均为 12 号浅灰。元信息第二行 N 张照片与查看相册 用紫色 12 号与第一行浅灰形成数据 vs 动作的语义区分——紫色暗示可点击。整卡交互点击任意位置 Toast 活动名ForEachkey 用e.id.toString()。两行元信息的排版价值每行都用左标签 右补充的layoutWeight(1)结构四行信息名称/日期人数/照片入口信息密度高但绝不拥挤是活动类列表卡的成熟模板。四、跨页数据自洽活动页是首页相册的来源活动页与首页、我的页的数据关系形成完整闭环同名呼应活动页 4 个活动迎新晚会/秋季运动会/校园音乐节/话剧社公演与首页 6 个相册中的 4 个完全同名——首页相册即活动照片集活动页负责活动视角、首页负责相册视角同一个数据源两种切片。照片数一致迎新晚会 128、运动会 256、音乐节 176、话剧 45与首页相册的count字段完全一致——同一份数据两处展示。参与人数320/580/450/120 是活动维度独有字段首页未展示——两页信息互补拼起来才是完整活动画像。我的页12 参与活动↔ Banner12 场活动↔ 活动页 4 个 已结束 8 个12 是平台/个人活动总数与分段进行中/已结束的状态划分呼应。五、实机截图与交互演示本节结合 4 张实机截图逐张还原活动页的视觉效果与交互过程。1. 活动页首屏标题 分段 活动卡第一张截图是活动页默认首屏顶部活动标题下方进行中 / 已结束分段——默认进行中为紫色加粗选中态已结束为灰色下方是第一张活动卡 2026 迎新晚会120 高 emoji 大图 名称 9月10日 320 人参与 128 张照片 查看相册 底部可见第二张 秋季运动会卡的上半部分。2. 点击已结束分段切换状态第二张截图是点击已结束分段后的状态高亮从进行中切换到已结束紫色加粗State tab由 0 变 1、UI 即时重绘。虽然 Demo 中列表内容不变两段共用数据但分段切换的交互反馈完整可验证为真实产品按状态过滤活动预留了结构。3. 点击活动卡弹出活动名 Toast第三张截图是点击第一张活动卡任意位置后的反馈弹出2026 迎新晚会Toast。整卡挂载onClick、闭包捕获e.name点击卡面任何区域大图区/名称/元信息都触发同一反馈点击热区大、误触率低。4. 滚动到底全部活动卡可见第四张截图是滚动到底部的视图第三张 校园音乐节与第四张 话剧社公演完整露出四张活动卡全部可见。每张卡的 120 高 emoji 大图区 三行信息的结构整齐划一列表滚动流畅底部安全区内边距保证 Tab 栏可点。六、扩展思考分段切换的三种实现方案活动页用文本 State实现了分段切换工程上还有更丰富的方案文本模拟本页方案ForEach 条件样式 State索引。最轻量、零依赖适合 2-4 个分段缺点是缺少滑动动画与无障碍语义。Tabs TabContentArkUI 原生分段容器自带滑动切换动画与手势适合分段内容差异大、需要独立滚动的场景缺点是结构较重每段需要独立内容区。分段指示条在选中 Text 下方渲染一个 2-3 高的圆角条State驱动的位移或条件渲染配合animation实现滑动指示动画——比纯文本高亮更精致是电商/资讯类 App 的常见做法。胶囊分段把选中项包成紫色圆角胶囊类似兴趣页选中态未选中为浅底——视觉更按钮化适合操作型分段。本页的文本模拟方案在只有两个分段、内容未分源的 Demo 阶段完全够用四种方案的演进路径清晰。七、扩展思考活动数据模型的完整设计从活动页的Event接口反推真实产品的活动模型基础字段{ id, emoji, name, date, photos, joined }已覆盖展示所需真实产品需扩展coverUrl封面图、status进行中/已结束/未开始、location地点、organizer主办方、description简介。status 驱动分段tab 0 ? events.filter(e e.status ongoing) : events.filter(e e.status ended)——分段切换从改高亮升级为过滤数据一行动态过滤即可。照片与活动的关系一个活动对应一个相册一对多activity → photos活动卡的 N 张照片即相册的 count——首页相册与活动页共享这张映射表。参与人数joined可实时增长用户点参加按钮 1配合上传页的关联活动胶囊迎新晚会/秋季运动会/校园音乐节/话剧公演上传照片即写入对应活动的照片集——三页联动的数据总线就此打通。八、常见问题与开发避坑分段切换没变化Demo 两段共用同一列表用户切换后只见高亮变化、不见内容变化可能误以为 Bug。真实实现必须绑定不同数据源否则建议在 Demo 文案中说明切换仅改变状态高亮。textAlign 需要固定宽度layoutWeight(1)已使 Text 占满列宽此时textAlign(TextAlign.Center)才能生效若 Text 宽度自适应内容居中无效。emoji 大图区的溢出50 号 emoji 在 120 高容器内垂直居中justifyContent(FlexAlign.Center)若 emoji 换成真实图片记得加objectFit(ImageFit.Cover)裁切否则图片会拉伸变形。圆角与图片裁切与首页同理若大图区放网络图片需外层容器clip(true)否则图片溢出圆角。列表空态若某分段无活动如已结束暂无数据页面只剩标题一片空白——应补充空态视图暂无已结束活动 图标工程化必备。九、扩展思考活动详情页与参与流程设计活动页的卡片点击后当前 Toast应进入活动详情页围绕了解活动 → 参与活动 → 回顾照片设计完整流程详情页信息架构封面大图 活动名 时间/地点/主办方可复用活动卡的四行信息结构放大 活动简介 参与/已参与状态按钮 相册入口 评论区。活动卡已有的date/joined/photos字段全部成为详情页的头图信息。参与状态机未参与 → 已参与 → 活动结束三态——对应分段进行中/已结束进行中的活动可点参加joined 1已结束的活动展示回顾照片。State joined: boolean驱动按钮文案与色态切换。倒计时组件进行中的活动可在详情页头部展示距开始还有 N 天setInterval定时刷新增强紧迫感与参与动力——ohos.timer或 ArkUI 定时器可实现。活动与照片的联动详情页相册入口跳转首页对应相册活动结束时相册自动封存并计入已结束分段——活动状态驱动照片可见性是活动照片共享类产品的核心业务规则。分享传播详情页配分享按钮生成活动海报封面 时间 参与人数分享到社交平台为平台引流——照片社区的拉新入口。十、扩展思考时间线与活动的生命周期管理从活动页的日期字段9月10日/10月15日/11月2日/11月20日可以展开活动的完整生命周期生命周期四阶段筹备中 → 进行中 → 已结束 → 归档——当前 Demo 只有进行中/已结束两态真实产品还有未开始预热报名与已归档照片长期可查两个阶段。状态自动流转系统按当前日期与date对比自动更新状态——new Date() date ? ended : ongoing无需人工干预配合onPageShow刷新App 打开即是最新状态。照片的时段属性活动照片可按拍摄时间细分开幕式/比赛/闭幕式相册内提供时间线滑动筛选——ohos.data的按时间查询能力支撑。历史活动沉淀已结束活动不删数据照片持续开放浏览甚至支持按届数归档2026 迎新晚会 vs 2025 迎新晚会平台内容随时间沉淀Banner已收录 12 场活动 · 858 张照片即这种沉淀的量级体现。统计与运营参与人数、照片数、获赞数按活动聚合可支撑运营看板哪类活动最受欢迎——数据在活动卡上已有雏形聚合查询是进阶能力。十一、系列横向对比活动清单类页面的四种范式活动页属于清单 状态筛选类页面本系列提供了多种可对照的实现范式范式代表页筛选方式列表形态分段切换App 40 活动页进行中/已结束文本分段图文大卡分类胶囊App 38 技能交换6 类横滑胶囊双行技能卡搜索过滤App 37 考试资料搜索框 分类资料列表Tab 页签App 34 打印资料底部 Tab 内分组资料卡App 40 用双段文本切换覆盖了活动清单最核心的筛选诉求当前/历史交互成本最低、用户零学习成本而 App 38 的横滑胶囊适合分类多且需要快速切换的场景App 37 的搜索适合资料量大需要精确检索的场景。筛选控件的选型取决于备选数量2-3 个状态用分段、4-8 个分类用横滑胶囊、大量条目用搜索——这是清单类产品设计的第一决策点。活动卡本身的信息结构emoji 大图 名称 两行元信息与 App 38 技能卡头像 名称 标签 按钮同属图文卡家族但活动卡弱化操作按钮查看相册 是文字链而非按钮、强化数据信息日期/人数/照片数——因为活动的转化动作是低频的报名/查看而技能的交换是高频操作。信息组织的优先级永远服务于核心动作这一原则在两张卡片的设计差异中体现得淋漓尽致。十二、开发者视角分段切换与列表联动的调试技巧State 切换无效的排查若点击分段后高亮不变化先确认onClick是否真正触发可临时加 console 日志再确认State tab是否被正确赋值——常见坑是this.tab idx写成了局部变量赋值。分段与列表的数据过滤产品化后tab 0 ? 进行中 : 已结束的过滤逻辑建议写成计算属性get currentEvents()避免在构建函数里写复杂条件分支——既清晰又便于单测。大图区的图片替换把 emoji 换成真实活动封面时务必加objectFit(ImageFit.Cover)与固定宽高否则不同尺寸的封面会拉伸变形破坏卡片统一性——回归测试时用竖图、横图、方形图各试一遍。日期显示与时区 9月10日若来自服务端 ISO 日期注意时区转换UTC → 本地否则可能显示成 9 月 9 日——用ohos.i18n的日期格式化接口做本地化。列表滚动性能活动卡含 120 高图片区 三行文字若数量上百应把ForEach升级为LazyForEach并按 id 缓存图片——滚动卡顿时优先检查是否有整列表重建如 key 不稳定。十三、FAQ 与一句话总结Q1活动页和首页相册有什么区别活动页以活动为维度时间/参与人数/状态首页以相册为维度照片数量/瀑布流展示。二者共享同一批照片数据是同一内容源的两种组织视角——一个问办了哪些活动一个问有哪些相册可看。Q2分段切换为什么不做成可滑动的两段内容共用列表滑动切换无实际意义。当分段内容真正分离进行中列表 vs 已结束列表时可升级为Tabs获得滑动动画。Q3查看相册 为什么点整卡都是弹活动名整卡统一挂载 onClick 弹活动名查看相册 没有单独挂事件——原型阶段一个点击入口足够。产品化时给查看相册 单独挂跳转进入相册详情页整卡点击与入口跳转可并存。Q4日期格式为什么是9月10日而非2026-09-10面向 C 端展示用友好格式9月10日比标准格式更亲切是产品文案的常见选择数据层仍应存标准 ISO 日期展示层再做格式化。Q5为什么只有 4 个活动4 张卡恰好一屏展示主体 滚动留白信息量适中。真实产品分页加载首屏 10 条左右为佳。一句话总结活动页用双行 Header 文本分段 四行信息活动卡完成了活动清单 状态筛选的产品职能。分段切换的State驱动、两行元信息的layoutWeight分列、emoji 大图区与三行信息区图文卡结构都是 ArkUI 列表页的高频手法——尤其数据行浅灰、动作行紫色的颜色语义化是本页最值得抄走的细节。再补充一点观察活动页的 Header 是二级页中少见的标题 分段双行结构这一差异源于活动清单的状态筛选需求——分段行成为页面交互的副导航与内容区形成筛选驱动列表的联动关系。若未来活动数量增长到几十个可在分段下方追加按月份筛选的横向滚动月份条让活动清单演化为完整的校园活动时间线。同时活动卡的joined参与人数与photos照片数两个数据字段已具备活动热度的雏形——产品化后可用joined * 0.7 photos * 0.3计算热度分支持热门活动排序让列表从固定顺序升级为热度驱动进一步贴近真实运营场景。活动页虽仅 89 行却是清单 筛选 数据三要素俱全的完整页面。最后从验收视角看四张实机截图覆盖了首屏分段 第一张活动卡、分段切换已结束高亮、卡片点击活动名 Toast、滚动底部全部四卡可见四个关键状态证明State tab切换、整卡点击、列表滚动三项核心交互均工作正常。迎新晚会 128 张等数据与页面内其他位置一致再次验证了数据自洽的验收标准。 整体而言本页以最小的代码量实现了清单、筛选、数据三类能力配合四张实机截图的完整验证为校园活动场景交出了一份高质量的参考实现。