HarmonyOS 实战教程(四):首页布局实现 —— Swiper 轮播、Grid 网格与组件化 —— 以「柚兔自测量表」为例

HarmonyOS 实战教程(四):首页布局实现 —— Swiper 轮播、Grid 网格与组件化 —— 以「柚兔自测量表」为例
一、首页整体结构MeCharts 首页HomeView承载了所有量表入口整体结构为顶部导航栏 可滚动内容区轮播图 分类网格。PreviewComponentV2exportstruct HomeView{LocalglobalInfoModel:GlobalInfoModelAppStorage.get(GlobalInfoModel)||newGlobalInfoModel()privatepageContext:PageContextAppStorage.get(pageContext)asPageContext;LocalimgHeight:number190LocalimgWidth:number264LocalimgList:Resource[]newArray(3).fill().map((item:string,index){return$r(app.media.banner_0${index1})})privateasdList:AbcModel[][newAbcModel($r(app.media.ic_item_abc),ABC量表,(自闭症行为评定量表),1),newAbcModel($r(app.media.ic_item_cars),CARS量表,(儿童期孤独症评定量表),2),newAbcModel($r(app.media.ic_item_move),多动症量表,(多动症诊断标准量表),3),]privatecareerList:AbcModel[][newAbcModel($r(app.media.ic_item_mbti),MBTI测试,(MBTI职业性格测试完整版),1),]privateemotionList:AbcModel[][newAbcModel($r(app.media.ic_item_depress),SDS量表,(抑郁自评量表),1),newAbcModel($r(app.media.ic_item_anxious),SAS量表,(焦虑症自评量表),2),newAbcModel($r(app.media.ic_item_relationship),ECR量表,(亲密关系经历量表),3),]build(){Column(){this.buildTopBar();this.buildContentView();}.height(100%).width(100%).backgroundColor($r(app.color.color_background))}}1.1 数据模型设计所有量表入口使用统一的AbcModel数据模型ObservedexportclassAbcModel{img:Resource|undefinedundefinedtitle:stringsubTitle:stringid:number0score?:stringtype?:number0constructor(img:Resource,title?:string,subTitle?:string,id?:number,score?:string,type?:number){// 构造函数赋值...}}Observed装饰器使该类的实例可被 ArkUI 框架观测当属性变化时自动触发 UI 刷新。这在历史记录页面中更新分数显示时非常关键。二、Swiper 轮播组件2.1 基本使用首页顶部使用UISwiperAGConnect 提供的增强轮播组件展示推荐量表UISwiper({imgWidth:this.imgWidth,imgHeight:this.imgHeight,imgList:this.imgList,isLoop:true,isCovered:false,onImageClick:(index:number){if(index0){this.pageContext.openPage({param:{title:MBTI测试}asResultParams,routerName:MbtiListPage,},true);}elseif(index1){this.pageContext.openPage({param:{title:ABC量表}asResultParams,routerName:AbcListPage,},true);}elseif(index2){this.pageContext.openPage({param:{title:SAS量表,type:FormType.TYPE_SDS}asResultParams,routerName:MoveListPage,},true);}}})轮播图的点击事件通过onImageClick回调处理根据索引跳转到不同量表页面。2.2 原生 Swiper 的使用方式如果使用原生 Swiper 组件基础用法如下Swiper(){ForEach(this.imgList,(img:Resource){Image(img).width(this.imgWidth).height(this.imgHeight).borderRadius(12).onClick((){// 点击跳转逻辑})})}.autoPlay(true).interval(3000).indicator(true).loop(true).cachedCount(2)原生 Swiper 的关键属性属性说明autoPlay是否自动播放interval自动播放间隔msindicator是否显示导航指示器loop是否循环播放cachedCount预缓存页面数三、Grid 网格布局3.1 分类网格实现首页使用 Grid 布局展示三大分类的量表入口BuilderbuildAbc(){// 分类标题Row({space:10}){Text().width(3).height(15).backgroundColor($r(app.color.color_default));Text(自闭症相关).fontWeight(FontWeight.Bold).fontSize(16)}.margin({left:12})// 量表网格Grid(){ForEach(this.asdList,(asd:AbcModel,index){GridItem(){Column({space:8}){Row({space:8}){Image(asd.img).width(24);Text(asd.title).fontWeight(FontWeight.Medium);};Text(asd.subTitle).fontSize(12);}.alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center).borderRadius(15).width(100%).height(100%).backgroundColor($r(app.color.color_card))}.onClick((){// 跳转到对应量表页面})})}.padding(12).columnsTemplate(1fr 1fr)// 两列等宽.rowsTemplate(1fr 1fr)// 两行等高.columnsGap(10).rowsGap(10).width(100%).height(160)}3.2 Grid 核心属性columnsTemplate / rowsTemplate是 Grid 最核心的属性定义了网格的行列结构.columnsTemplate(1fr 1fr)// 两列每列等宽.rowsTemplate(1fr 1fr)// 两行每行等高fr是分数单位1fr 1fr表示两列各占 1/2。更复杂的布局如.columnsTemplate(1fr 2fr 1fr)// 三列中间列是两侧的两倍宽.rowsTemplate(auto auto)// 两行高度由内容决定columnsGap / rowsGap控制行列间距.columnsGap(10)// 列间距 10vp.rowsGap(10)// 行间距 10vp3.3 不同分类的布局差异MeCharts 根据量表数量灵活调整布局分类量表数量布局方式高度自闭症相关3个2列×2行160职业性格相关1个2列×1行80情绪相关3个2列×2行160职业性格分类只有一个量表使用单行布局其他分类使用 2×2 网格空位自然留白。四、TopBar 通用顶部导航栏4.1 组件设计TopBar 是全应用复用率最高的组件支持标题、返回按钮和右侧自定义内容ComponentV2exportstruct TopBar{privateglobalInfoModel:GlobalInfoModelAppStorage.get(GlobalInfoModel)||newGlobalInfoModel();Paramtitle:stringParamshowBackButton:booleantrueParambgColor:ResourceColor$r(app.color.color_default)ParamtitleColor:ResourceColorColor.WhiteParambarHeight:number80ParamstatusBarHeight:numberthis.globalInfoModel.statusBarHeightEventonBack?:()void|booleanBuilderParamrightContent?:()voidhandleBack(){if(this.onBack){constresultthis.onBack()if(resultfalse){return// 返回 false 可阻止默认行为}}}build(){RelativeContainer(){if(this.showBackButton){Image($r(app.media.ic_back)).width(20).height(20).id(backBtn).alignRules({left:{anchor:__container__,align:HorizontalAlign.Start},center:{anchor:__container__,align:VerticalAlign.Bottom}}).onClick((){this.handleBack()})}Text(this.title).fontSize(18).fontWeight(FontWeight.Bold).fontColor(this.titleColor).id(title).alignRules({center:{anchor:__container__,align:VerticalAlign.Bottom},middle:{anchor:__container__,align:HorizontalAlign.Center}})if(this.rightContent){Row(){this.rightContent()}.id(rightContent).alignRules({right:{anchor:__container__,align:HorizontalAlign.End},center:{anchor:__container__,align:VerticalAlign.Bottom}})}}.width(100%).height(this.barHeight).backgroundColor(this.bgColor).padding({top:this.statusBarHeight,bottom:20,left:12,right:12})}}4.2 RelativeContainer 相对布局TopBar 使用RelativeContainer实现左右中三栏布局这是 HarmonyOS 提供的相对定位容器返回按钮锚定容器左侧 垂直居中标题锚定容器水平居中 垂直居中右侧内容锚定容器右侧 垂直居中相比 Flex 布局RelativeContainer 在处理左右对齐 中间居中的场景时更简洁。4.3 使用示例首页使用 TopBar无返回按钮 自定义右侧TopBar({title:自测量表,showBackButton:false,rightContent:(){this.buildRightContent()},})子页面使用 TopBar有返回按钮TopBar({title:this.title,onBack:(){this.pageContext.popPage(true)}})五、ComponentV2 与 Component 的选择MeCharts 中两种组件声明方式并存ComponentV2新版本装饰器支持Param、Event、Local、Monitor等类型安全更好Component经典版本装饰器支持Prop、Link、State等特性ComponentComponentV2状态装饰器State, Prop, LinkLocal, Param, Event状态观测基于代理基于拦截器性能更优参数传递构造函数传入Param 声明式事件回调箭头函数Event 装饰器监听变化WatchMonitor新项目推荐优先使用ComponentV2。六、小结本篇讲解了首页的 Swiper 轮播、Grid 网格布局和 TopBar 通用组件的设计实现。通过组件化封装和统一数据模型首页的代码结构清晰、复用性强。下一篇将深入量表答题页面的实现讲解自定义 Radio 组件与表单交互。