HarmonyOS Next智能家居控制面板开发指南 原创

SameX
发布于 2025-2-28 10:46
浏览
0收藏

本文旨在深入探讨华为鸿蒙HarmonyOS Next系统的技术细节,基于实际开发实践进行总结。主要作为技术分享与交流载体,难免错漏,欢迎各位同仁提出宝贵意见和问题,以便共同进步。本文为原创内容,任何形式的转载必须注明出处及原作者。

在智能家居蓬勃发展的当下,开发一款适配多种设备且交互友好的智能家居控制面板显得尤为重要。借助HarmonyOS Next的强大能力,我们可以打造出功能丰富、界面美观且操作便捷的控制面板。下面,让我们一步步深入了解其开发过程。

智能家居应用的UI设计思路

核心功能拆解:设备控制、场景管理、数据展示

智能家居控制面板的核心功能主要包括设备控制、场景管理和数据展示。设备控制是基础功能,用户可以通过控制面板对家中的各类智能设备,如插座、灯光、空调等进行开关、调节参数等操作。场景管理则允许用户根据自己的生活习惯,预设不同的场景模式,比如“回家模式”“睡眠模式”等,一键实现多个设备的协同控制。数据展示功能用于呈现设备的运行状态、环境数据(如温度、湿度)等信息,方便用户实时了解家中的智能设备情况。

大屏vs小屏的UI差异:如何在手机、平板、智慧屏上呈现不同的布局

不同设备的屏幕尺寸和交互方式差异较大,因此在UI布局上需要有所区分。

  • 手机:手机屏幕相对较小,操作主要依赖触摸。UI布局应简洁明了,突出核心功能。通常采用底部Tab切换的方式,方便用户单手操作。例如,将“设备控制”“场景管理”“数据展示”等功能模块分别放在不同的Tab中,用户通过点击Tab即可快速切换界面。
  • 平板:平板屏幕较大,兼具一定的便携性和操作空间。可以采用双栏模式,一侧展示设备列表,另一侧展示选中设备的详情或操作界面。这样既能展示较多信息,又能方便用户快速选择和操作设备。
  • 智慧屏:智慧屏屏幕更大,用于客厅等场景的集中控制。采用三栏模式较为合适,左侧为侧边栏,用于导航和切换不同功能模块;中间展示设备列表,以较大的卡片形式呈现,方便远距离操作;右侧展示当前选中设备的详细信息和操作面板,充分利用大屏优势,展示更多细节和操作选项。

采用SideBarContainer + Navigation + Grid实现动态布局

大屏设备:三栏模式(侧边栏 + 设备列表 + 设备详情)

在大屏设备上,我们利用SideBarContainer创建侧边栏,Navigation管理页面切换和内容展示,Grid进行设备列表的布局。示例代码如下:

@Entry
@Component
struct BigScreenPanel {
    @State selectedDevice: string = ''
    @State deviceList: string[] = ['插座', '灯光', '空调']
    @State deviceDetails: { [key: string]: string } = {
        '插座': '插座状态:开',
        '灯光': '灯光亮度:50%',
        '空调': '温度:26℃'
    }
    build() {
        SideBarContainer(SideBarContainerType.Embed) {
            // 侧边栏
            Column() {
                ForEach(['设备控制', '场景管理', '数据展示'], (item) => {
                    Text(item).fontSize(20).onClick(() => {
                        // 侧边栏点击逻辑
                    })
                })
            }
              .width('20%')
              .backgroundColor('#F1F3F5')
            Column() {
                // 设备列表
                GridRow() {
                    ForEach(this.deviceList, (device) => {
                        GridCol({ span: 4 }) {
                            Column() {
                                Text(device).fontSize(18).onClick(() => {
                                    this.selectedDevice = device
                                })
                            }
                              .padding(10)
                              .backgroundColor('#FFFFFF')
                              .borderRadius(10)
                        }
                    })
                }
                // 设备详情
                Column() {
                    Text(this.deviceDetails[this.selectedDevice] || '').fontSize(16).padding(10)
                }
            }
              .width('80%')
        }
          .sideBarWidth('20%')
          .showSideBar(true)
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.

小屏设备:双栏模式(底部Tab切换 + 设备详情页)

小屏设备上,通过底部Tab切换不同功能页面,利用Navigation组件实现页面间的切换,Grid用于设备详情页的布局。示例代码如下:

@Entry
@Component
struct SmallScreenPanel {
    @State currentTab: number = 0
    @State selectedDevice: string = ''
    @State deviceList: string[] = ['插座', '灯光', '空调']
    @State deviceDetails: { [key: string]: string } = {
        '插座': '插座状态:开',
        '灯光': '灯光亮度:50%',
        '空调': '温度:26℃'
    }
    build() {
        Column() {
            if (this.currentTab === 0) {
                // 设备列表页
                GridRow() {
                    ForEach(this.deviceList, (device) => {
                        GridCol({ span: 12 }) {
                            Column() {
                                Text(device).fontSize(18).onClick(() => {
                                    this.selectedDevice = device
                                })
                            }
                              .padding(10)
                              .backgroundColor('#FFFFFF')
                              .borderRadius(10)
                        }
                    })
                }
            } else {
                // 设备详情页
                Column() {
                    Text(this.deviceDetails[this.selectedDevice] || '').fontSize(16).padding(10)
                }
            }
            Tabs({ barPosition: BarPosition.End }) {
                TabContent() {
                    // 设备控制页面
                }
                .tabBar(
                    Column() {
                        Image($r('app.media.device_control_icon')).width(24).height(24)
                        Text('设备控制').fontSize(12)
                    }
                  .justifyContent(FlexAlign.Center).height('100%').width('100%')
                )
                TabContent() {
                    // 场景管理页面
                }
                .tabBar(
                    Column() {
                        Image($r('app.media.scene_management_icon')).width(24).height(24)
                        Text('场景管理').fontSize(12)
                    }
                  .justifyContent(FlexAlign.Center).height('100%').width('100%')
                )
                TabContent() {
                    // 数据展示页面
                }
                .tabBar(
                    Column() {
                        Image($r('app.media.data_display_icon')).width(24).height(24)
                        Text('数据展示').fontSize(12)
                    }
                  .justifyContent(FlexAlign.Center).height('100%').width('100%')
                )
            }
              .barMode(BarMode.Fixed)
              .barWidth('100%')
              .barHeight(56)
              .onChange((index: number) => {
                    this.currentTab = index
                })
        }
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.

利用栅格布局动态调整设备卡片的排列方式(手机单列、平板双列、智慧屏三列)

借助栅格布局的灵活性,根据不同设备屏幕尺寸动态调整设备卡片的排列。通过设置GridColspan属性,在不同断点下实现不同的排列效果。示例代码如下:

@Entry
@Component
struct GridLayoutForDevices {
    @State currentBreakpoint: string ='sm'
    @State deviceList: string[] = ['插座', '灯光', '空调']
    build() {
        GridRow({ breakpoints: { value: ['600vp', '840vp'], reference: BreakpointsReference.WindowSize } }) {
            ForEach(this.deviceList, (device) => {
                GridCol({ span: { xs: 12, sm: 12, md: 6, lg: 4 } }) {
                    Column() {
                        Text(device).fontSize(18)
                    }
                      .padding(10)
                      .backgroundColor('#FFFFFF')
                      .borderRadius(10)
                }
            })
        }
          .onBreakpointChange((breakpoint: string) => {
                this.currentBreakpoint = breakpoint
            })
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.

在上述代码中,xssm断点下(对应手机屏幕尺寸),设备卡片单列显示;md断点下(对应平板屏幕尺寸),双列显示;lg断点下(对应智慧屏屏幕尺寸),三列显示。

优化设备控制交互体验

使用响应式断点 让用户可以自由调整窗口大小,控制面板自动适配

通过设置响应式断点,监听窗口大小变化,在不同窗口尺寸下切换合适的布局。利用GridRow组件的breakpoints属性和onBreakpointChange事件,实现布局的动态调整。例如:

@Entry
@Component
struct ResponsivePanel {
    @State currentBreakpoint: string ='sm'
    build() {
        GridRow({ breakpoints: { value: ['600vp', '840vp'], reference: BreakpointsReference.WindowSize } }) {
            // 布局内容
        }
          .onBreakpointChange((breakpoint: string) => {
                this.currentBreakpoint = breakpoint
            })
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.

在窗口大小改变时,onBreakpointChange回调函数会被触发,从而更新布局状态,确保控制面板在自由窗口模式下也能保持良好的显示效果。

组件化设计:如何封装可复用的智能设备UI组件(插座、灯光、空调等)

为了提高开发效率和代码的可维护性,将不同智能设备的UI组件进行封装。以灯光组件为例:

@Component
struct LightComponent {
    @Prop isOn: boolean
    @Prop brightness: number
    @State isEditing: boolean = false
    build() {
        Column() {
            Text('灯光').fontSize(18)
            if (this.isEditing) {
                // 编辑模式,可调整亮度
                Slider({ value: this.brightness * 100, min: 0, max: 100, style: SliderStyle.OutSet })
                  .blockColor(Color.White)
                  .width('80%')
                  .onChange((value: number) => {
                        // 更新亮度逻辑
                    })
            } else {
                // 普通模式,显示状态
                Text(this.isOn? '已开启' : '已关闭').fontSize(16)
                Text(`亮度:${this.brightness * 100}%`).fontSize(14)
            }
            Button(this.isEditing? '完成' : '编辑').onClick(() => {
                this.isEditing =!this.isEditing
            })
        }
          .padding(10)
          .backgroundColor('#FFFFFF')
          .borderRadius(10)
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.

在主控制面板中,可以这样使用该组件:

@Entry
@Component
struct MainPanel {
    @State lightIsOn: boolean = true
    @State lightBrightness: number = 0.5
    build() {
        Column() {
            LightComponent({ isOn: this.lightIsOn, brightness: this.lightBrightness })
        }
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

手势与远程控制优化:支持滑动调整亮度、点击切换开关、语音控制适配

在触摸设备上,通过添加触摸事件监听器,实现滑动调整亮度和点击切换开关的功能。对于语音控制,借助HarmonyOS Next的语音识别能力,识别用户语音指令并执行相应操作。示例代码如下:

@Component
struct InteractiveLightComponent {
    @Prop isOn: boolean
    @Prop brightness: number
    @State isEditing: boolean = false
    build() {
        Column() {
            Text('灯光').fontSize(18)
            if (this.isEditing) {
                Slider({ value: this.brightness * 100, min: 0, max: 100, style: SliderStyle.OutSet })
                  .blockColor(Color.White)
                  .width('80%')
                  .onChange((value: number) => {
                        // 更新亮度逻辑
                    })
            } else {
                Text(this.isOn? '已开启' : '已关闭').fontSize(16)
                Text(`亮度:${this.brightness * 100}%`).fontSize(14)
            }
            Button(this.isEditing? '完成' : '编辑').onClick(() => {
                this.isEditing =!this.isEditing
            })
        }
          .padding(10)
          .backgroundColor('#FFFFFF')
          .borderRadius(10)
          .onTouch((event) => {
                if (event.type === TouchType.Swipe) {
                    // 根据滑动方向调整亮度逻辑
                } else if (event.type === TouchType.Click) {
                    // 点击切换开关逻辑
                }
            })
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.

对于语音控制,首先需要初始化语音识别功能,然后在识别到相应指令时,调用设备控制函数:

import { speech } from '@ohos.speech';

@Entry
@Component
struct VoiceControlledPanel {
    @State lightIsOn: boolean = true
    @State lightBrightness: number = 0.5
    aboutToAppear() {
        speech.init({
            onResult: (result) => {
                if (result.includes('打开灯光')) {
                    this.lightIsOn = true
                } else if (result.includes('关闭灯光')) {
                    this.lightIsOn = false
                } else if (result.includes('调亮灯光')) {
                    this.lightBrightness = Math.min(1, this.lightBrightness + 0.1)
                } else if (result.includes('调暗灯光')) {
                    this.lightBrightness = Math.max(0, this.lightBrightness - 0.1)
                }
            },
            onError: (error) => {
                console.error('语音识别错误:', error)
            }
        })
        speech.start()
    }
    aboutToDisappear() {
        speech.stop()
    }
    build() {
        Column() {
            InteractiveLightComponent({ isOn: this.lightIsOn, brightness: this.lightBrightness })
        }
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.

通过上述设计和实现,我们可以打造出一个功能完善、交互友好且适配多种设备的智能家居控制面板,充分发挥HarmonyOS Next的优势,为用户提供便捷的智能家居控制体验。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
分类
标签
收藏
回复
举报


回复
    相关推荐
    加入我们,一起打造面向云时代的开源操作系统!
    觉得TA不错?点个关注精彩不错过
    641
    帖子
    189
    视频
    3806
    声望
    38
    粉丝
    社区精华内容