HarmonyOS智能家居——安防中心页面实现详解

📅 2026/7/14 4:54:48
HarmonyOS智能家居——安防中心页面实现详解
安防中心是智能家居 App 里功能最独立的页面——它不依赖 DeviceData 服务层所有数据都在页面内部的State里管理。从截图看页面分三个区域顶部两个状态卡片门锁和警报中间摄像头列表底部快捷操作按钮。实现上用了两个 BuilderStatusCard 和 ActionBtn代码量不大但有几个值得注意的设计细节。完整效果数据结构interfaceCam{name:string;icon:string;online:boolean}Statecams:Cam[][{name:门口摄像头,icon:,online:true},{name:客厅摄像头,icon:,online:true},{name:车库摄像头,icon:,online:false},]Statealarm:booleantrueStatedoorLocked:booleantrue三个State变量管理所有安防数据摄像头列表、警报状态、门锁状态。和首页的设备数据不同安防数据完全独立——没有从 DeviceData 读取任何信息也没有暴露给其他页面。这是合理的因为安防系统的数据结构摄像头在线状态、布防状态和设备系统开关、亮度、温度差别很大强行放在同一个数据层里反而增加复杂度。门锁和警报的状态卡片Row({space:12}){this.StatusCard(,门锁,this.doorLocked?已锁定:未锁定,this.doorLocked?#00B894:#FF6B6B)this.StatusCard(,警报,this.alarm?已布防:已撤防,this.alarm?#00B894:#FF6B6B)}.width(100%).padding({left:16,right:16})两个 StatusCard 并排显示每个卡片有四层信息图标、标签、状态文字、状态颜色。StatusCard BuilderBuilderStatusCard(icon:string,label:string,status:string,color:string){Column(){Text(icon).fontSize(28).margin({bottom:6})Text(label).fontSize(12).fontColor(T2)Text(status).fontSize(14).fontWeight(FontWeight.Bold).fontColor(color).margin({top:4})}.layoutWeight(1).padding(16).backgroundColor(#FFFFFF).borderRadius(14)}四个参数分别控制图标、标签文字、状态文字、状态颜色。layoutWeight(1)让两个卡片平分水平空间。状态文字的颜色根据状态动态变化——安全状态用绿色#00B894不安全状态用红色#FF6B6B。这种颜色编码在安防场景里是通用约定绿色安全红色警告。用户不需要读文字只看颜色就能判断当前安防状态。门锁和警报的切换逻辑// 门锁this.ActionBtn(,锁门,(){this.doorLocked!this.doorLocked})// 警报this.ActionBtn(,this.alarm?撤防:布防,(){this.alarm!this.alarm})门锁按钮点击时直接切换doorLocked的布尔值。警报按钮更巧妙——按钮文字也是动态的this.alarm ? 撤防 : 布防。当警报处于布防状态时按钮显示撤防告诉用户点击后会做什么当处于撤防状态时按钮显示布防。这种按钮文字反映当前操作的设计比固定的开关文字更直观——用户不需要先判断当前状态再决定要不要点按钮本身已经告诉了他点了之后会发生什么。摄像头列表ForEach(this.cams,(c:Cam){Row(){Text(c.icon).fontSize(32).width(56).height(56).borderRadius(14).backgroundColor(#F5F5FA).textAlign(TextAlign.Center)Column(){Text(c.name).fontSize(15).fontWeight(FontWeight.Bold).fontColor(T1)Text(c.online? 在线: 离线).fontSize(11).fontColor(T3)}.alignItems(HorizontalAlign.Start).margin({left:12}).layoutWeight(1)SymbolGlyph($r(sys.symbol.chevron_right)).fontSize(14).fontColor([#DDD])}.width(100%).padding(14).backgroundColor(#FFFFFF).borderRadius(14).margin({left:16,right:16})})每个摄像头卡片分三部分左侧 56×56 的 emoji 图标容器、中间名称和在线状态、右侧右箭头。在线状态用绿色圆点 “在线” 或红色圆点 “离线” 表示——和首页设备状态卡片的绿色圆点用的是同一套视觉语言。右箭头暗示点击可查看详情但目前没有绑定onClick事件是一个 UI 占位。Cam 接口的轻量设计interfaceCam{name:string;icon:string;online:boolean}三个字段足够了——名称用于显示emoji 用于图标在线状态用于判断。没有id字段因为摄像头列表不需要跳转到详情页右箭头只是占位。没有room字段因为摄像头的位置信息已经包含在名称里“门口”、“客厅”、“车库”。接口设计的原则是只存需要的字段——多余的字段不仅浪费内存还会让后续维护者困惑这个字段到底在哪里用到了。快捷操作按钮Row({space:12}){this.ActionBtn(,锁门,(){this.doorLocked!this.doorLocked})this.ActionBtn(,this.alarm?撤防:布防,(){this.alarm!this.alarm})this.ActionBtn(,报警,(){})}.width(100%).padding({left:16,right:16})三个操作按钮横向排列每个按钮接收图标、文字、回调三个参数。ActionBtn BuilderBuilderActionBtn(icon:string,label:string,action:()void){Column(){Text(icon).fontSize(28).margin({bottom:6})Text(label).fontSize(12).fontColor(T1)}.layoutWeight(1).padding(14).backgroundColor(#FFFFFF).borderRadius(14).onClick(action)}和 StatusCard 的结构一样——emoji 文字纵向排列白底圆角卡片。区别是 StatusCard 是纯展示没有 onClickActionBtn 是可交互的绑定了 onClick。报警按钮的空操作this.ActionBtn(,报警,(){})报警按钮的回调是空函数——点击后什么都不会发生。这是合理的真正的报警功能需要接入电话系统或紧急联系人在原型阶段无法实现。先放一个占位按钮告诉用户这里以后可以报警后续再接入实际功能。整个页面的状态管理特征安防页面的状态管理是所有页面里最简单的——没有数组操作、没有引用变更、没有跨页面同步。每个状态都是简单的布尔值切换this.doorLocked!this.doorLocked// 门锁this.alarm!this.alarm// 警报不需要复制数组 替换引用的套路因为State追踪的是变量本身的引用布尔值的切换会被直接检测到。这是因为安防页面的数据模型比其他页面简单得多——设备页面有 17 个设备的数组需要管理场景页面有 5 个场景的激活状态需要排他处理而安防页面只有两个布尔值和一个摄像头列表。数据模型的复杂度直接决定了状态管理的复杂度。两个 Builder 的对比维度StatusCardActionBtn参数数量4icon, label, status, color3icon, label, action交互无纯展示有onClick状态颜色动态传入固定黑色使用次数2 次3 次StatusCard 的参数比 ActionBtn 多一个color因为状态卡片需要根据安全状态改变文字颜色。ActionBtn 不需要颜色参数——按钮文字始终是黑色视觉焦点在图标和交互上。两个 Builder 的视觉结构几乎一样emoji 文字纵向排列 白底圆角卡片但职责不同。如果要强行合并成一个通用 Builder需要加一个interactive参数来区分是否绑定 onClick代码会变得更复杂。在当前规模下分开写两个 Builder 更清晰。页面间的数据独立性安防页面和其他页面之间没有数据交互不从 DeviceData 读取设备信息不向 DeviceData 写入安防状态ProfilePage 的菜单里没有安防入口首页的设备状态卡片不包含安防设备这种独立性是刻意的——安防系统的数据结构和设备系统完全不同强行关联会增加不必要的耦合。在真实的智能家居 App 里安防系统可能有自己独立的后端服务和数据存储前端只负责展示和控制。当前版本的安防数据全部是前端 mock没有持久化存储。刷新页面或退出 App 后门锁和警报状态会重置为默认值都是true。后续如果要做持久化可以用ohos.data.preferences把doorLocked和alarm存到本地。