项目已开源,开源地址: gitcode.com/nutpi/Harmo... , 欢迎fork & star
效果演示

1. 概述
本教程将详细讲解如何使用HarmonyOS NEXT中的GridRow和GridCol组件实现智能家居控制面板的网格布局。通过网格布局,我们可以创建一个直观、美观的智能家居控制界面,方便用户管理和控制家中的各种智能设备。
本教程将涵盖以下内容:
- 智能设备数据结构设计
- 数据准备
- 整体布局实现
- GridRow和GridCol组件配置
- 设备卡片实现
- 布局效果分析
2. 数据结构设计
首先,我们需要定义智能设备的数据结构,包含设备的基本信息:
typescript
// 智能设备类型
export interface DeviceType {
id: number; // 设备ID
name: string; // 设备名称
icon: Resource; // 设备图标
type: string; // 设备类型
room: string; // 所在房间
status: boolean; // 设备状态(开/关)
value?: number; // 设备值(如亮度、温度等)
color?: string; // 设备颜色(如灯光颜色)
}
// 房间类型
export interface RoomType {
id: number; // 房间ID
name: string; // 房间名称
icon: Resource; // 房间图标
deviceCount: number; // 设备数量
}
3. 数据准备
接下来,我们准备一些示例数据用于展示:
typescript
// 房间数据
private rooms: RoomType[] = [
{
id: 1,
name: '客厅',
icon: $r('app.media.ic_living_room'),
deviceCount: 5
},
{
id: 2,
name: '卧室',
icon: $r('app.media.ic_bedroom'),
deviceCount: 3
},
{
id: 3,
name: '厨房',
icon: $r('app.media.ic_kitchen'),
deviceCount: 4
},
{
id: 4,
name: '浴室',
icon: $r('app.media.ic_bathroom'),
deviceCount: 2
},
{
id: 5,
name: '书房',
icon: $r('app.media.ic_study'),
deviceCount: 3
}
];
// 智能设备数据
private devices: DeviceType[] = [
{
id: 1,
name: '客厅灯',
icon: $r('app.media.ic_light'),
type: 'light',
room: '客厅',
status: true,
value: 80,
color: '#FFD700'
},
{
id: 2,
name: '空调',
icon: $r('app.media.ic_ac'),
type: 'ac',
room: '客厅',
status: true,
value: 24
},
{
id: 3,
name: '电视',
icon: $r('app.media.ic_tv'),
type: 'tv',
room: '客厅',
status: false
},
{
id: 4,
name: '窗帘',
icon: $r('app.media.ic_curtain'),
type: 'curtain',
room: '客厅',
status: true,
value: 100
},
{
id: 5,
name: '音响',
icon: $r('app.media.ic_speaker'),
type: 'speaker',
room: '客厅',
status: false
},
{
id: 6,
name: '卧室灯',
icon: $r('app.media.ic_light'),
type: 'light',
room: '卧室',
status: false,
value: 0,
color: '#FFFFFF'
},
{
id: 7,
name: '床头灯',
icon: $r('app.media.ic_bedside_lamp'),
type: 'light',
room: '卧室',
status: true,
value: 30,
color: '#FFA07A'
},
{
id: 8,
name: '卧室空调',
icon: $r('app.media.ic_ac'),
type: 'ac',
room: '卧室',
status: true,
value: 26
},
{
id: 9,
name: '厨房灯',
icon: $r('app.media.ic_light'),
type: 'light',
room: '厨房',
status: false,
value: 0,
color: '#FFFFFF'
},
{
id: 10,
name: '冰箱',
icon: $r('app.media.ic_fridge'),
type: 'fridge',
room: '厨房',
status: true,
value: 4
},
{
id: 11,
name: '烤箱',
icon: $r('app.media.ic_oven'),
type: 'oven',
room: '厨房',
status: false
},
{
id: 12,
name: '洗碗机',
icon: $r('app.media.ic_dishwasher'),
type: 'dishwasher',
room: '厨房',
status: false
},
{
id: 13,
name: '浴室灯',
icon: $r('app.media.ic_light'),
type: 'light',
room: '浴室',
status: false,
value: 0,
color: '#FFFFFF'
},
{
id: 14,
name: '热水器',
icon: $r('app.media.ic_water_heater'),
type: 'water_heater',
room: '浴室',
status: true,
value: 45
},
{
id: 15,
name: '书房灯',
icon: $r('app.media.ic_light'),
type: 'light',
room: '书房',
status: true,
value: 70,
color: '#F5F5DC'
},
{
id: 16,
name: '台灯',
icon: $r('app.media.ic_desk_lamp'),
type: 'light',
room: '书房',
status: true,
value: 50,
color: '#F0E68C'
},
{
id: 17,
name: '书房空调',
icon: $r('app.media.ic_ac'),
type: 'ac',
room: '书房',
status: false,
value: 0
}
];
4. 布局实现
4.1 整体布局结构
我们将使用Column作为最外层容器,包含顶部状态栏、房间选择栏和设备网格列表:
typescript
build() {
Column() {
// 顶部状态栏
this.StatusBar()
// 房间选择栏
this.RoomSelector()
// 设备网格列表
this.DeviceGrid()
}
.width('100%')
.height('100%')
.backgroundColor('#F5F5F5')
}
4.2 顶部状态栏
typescript
@Builder
private StatusBar() {
Row() {
Column() {
Text('智能家居')
.fontSize(20)
.fontWeight(FontWeight.Bold)
.fontColor('#333333')
Text('欢迎回家,张先生')
.fontSize(14)
.fontColor('#666666')
.margin({ top: 4 })
}
.alignItems(HorizontalAlign.Start)
Blank()
Row() {
// 添加设备按钮
Button({ type: ButtonType.Circle }) {
Image($r('app.media.ic_add'))
.width(24)
.height(24)
}
.width(40)
.height(40)
.backgroundColor('#EEEEEE')
.margin({ right: 12 })
// 设置按钮
Button({ type: ButtonType.Circle }) {
Image($r('app.media.ic_settings'))
.width(24)
.height(24)
}
.width(40)
.height(40)
.backgroundColor('#EEEEEE')
}
}
.width('100%')
.padding({ left: 16, right: 16, top: 16, bottom: 16 })
.backgroundColor(Color.White)
}
4.3 房间选择栏
typescript
@State currentRoom: string = '全部';
@Builder
private RoomSelector() {
Scroll(ScrollDirection.Horizontal) {
Row() {
// 全部选项
Column() {
Image($r('app.media.ic_all_rooms'))
.width(40)
.height(40)
.margin({ bottom: 8 })
Text('全部')
.fontSize(14)
.fontColor(this.currentRoom === '全部' ? '#4285F4' : '#666666')
.fontWeight(this.currentRoom === '全部' ? FontWeight.Bold : FontWeight.Normal)
}
.width(80)
.height(80)
.padding(8)
.margin({ right: 12 })
.borderRadius(12)
.backgroundColor(this.currentRoom === '全部' ? '#E8F0FE' : Color.White)
.onClick(() => {
this.currentRoom = '全部';
})
// 各个房间选项
ForEach(this.rooms, (room: RoomType) => {
Column() {
Image(room.icon)
.width(40)
.height(40)
.margin({ bottom: 8 })
Text(room.name)
.fontSize(14)
.fontColor(this.currentRoom === room.name ? '#4285F4' : '#666666')
.fontWeight(this.currentRoom === room.name ? FontWeight.Bold : FontWeight.Normal)
}
.width(80)
.height(80)
.padding(8)
.margin({ right: 12 })
.borderRadius(12)
.backgroundColor(this.currentRoom === room.name ? '#E8F0FE' : Color.White)
.onClick(() => {
this.currentRoom = room.name;
})
})
}
.padding({ left: 16, right: 16 })
}
.scrollBar(BarState.Off)
.width('100%')
.margin({ top: 16, bottom: 16 })
}
4.4 设备网格列表
这是本教程的核心部分,我们使用GridRow和GridCol组件实现设备网格列表:
typescript
@Builder
private DeviceGrid() {
Column() {
// 标题栏
Row() {
Text(this.currentRoom === '全部' ? '所有设备' : `${this.currentRoom}设备`)
.fontSize(18)
.fontWeight(FontWeight.Bold)
.fontColor('#333333')
Blank()
Text(`${this.getFilteredDevices().length}个设备`)
.fontSize(14)
.fontColor('#666666')
}
.width('100%')
.padding({ left: 16, right: 16, bottom: 12 })
// 使用GridRow和GridCol实现网格布局
Scroll() {
GridRow({
columns: { xs: 2, sm: 2, md: 3, lg: 4 },
gutter: { x: 16, y: 16 }
}) {
ForEach(this.getFilteredDevices(), (device: DeviceType) => {
GridCol() {
this.DeviceCard(device)
}
})
}
.width('100%')
.padding(16)
}
.scrollBar(BarState.Off)
.scrollable(ScrollDirection.Vertical)
.width('100%')
.layoutWeight(1)
}
.width('100%')
.layoutWeight(1)
.backgroundColor('#F5F5F5')
.borderRadius({ topLeft: 24, topRight: 24 })
}
4.5 设备卡片实现
typescript
@Builder
private DeviceCard(device: DeviceType) {
Column() {
// 设备图标和状态
Row() {
Image(device.icon)
.width(24)
.height(24)
.fillColor(device.status ? '#4285F4' : '#999999')
Blank()
Toggle({ type: ToggleType.Switch, isOn: device.status })
.width(40)
.height(24)
.selectedColor('#4285F4')
.onChange((isOn: boolean) => {
this.toggleDevice(device.id, isOn);
})
}
.width('100%')
// 设备名称
Text(device.name)
.fontSize(16)
.fontWeight(FontWeight.Medium)
.fontColor('#333333')
.margin({ top: 12 })
// 设备状态文本
Text(this.getDeviceStatusText(device))
.fontSize(14)
.fontColor('#666666')
.margin({ top: 4 })
// 设备控制组件(根据设备类型显示不同控制)
if (device.type === 'light' && device.status) {
// 灯光亮度控制
Column() {
Row() {
Image($r('app.media.ic_brightness'))
.width(16)
.height(16)
.margin({ right: 8 })
Text('亮度')
.fontSize(14)
.fontColor('#666666')
Blank()
Text(`${device.value}%`)
.fontSize(14)
.fontColor('#4285F4')
}
.width('100%')
.margin({ top: 12 })
Slider({
value: device.value,
min: 0,
max: 100,
step: 1,
style: SliderStyle.OutSet
})
.width('100%')
.margin({ top: 8 })
.selectedColor('#4285F4')
.onChange((value: number) => {
this.updateDeviceValue(device.id, value);
})
}
.width('100%')
} else if (device.type === 'ac' && device.status) {
// 空调温度控制
Row() {
Button('-')
.width(32)
.height(32)
.fontSize(16)
.fontColor('#666666')
.backgroundColor('#EEEEEE')
.borderRadius(16)
.onClick(() => {
if (device.value > 16) {
this.updateDeviceValue(device.id, device.value - 1);
}
})
Text(`${device.value}°C`)
.fontSize(16)
.fontColor('#4285F4')
.fontWeight(FontWeight.Bold)
.margin({ left: 12, right: 12 })
Button('+')
.width(32)
.height(32)
.fontSize(16)
.fontColor('#666666')
.backgroundColor('#EEEEEE')
.borderRadius(16)
.onClick(() => {
if (device.value < 30) {
this.updateDeviceValue(device.id, device.value + 1);
}
})
}
.width('100%')
.margin({ top: 12 })
.justifyContent(FlexAlign.Center)
}
}
.width('100%')
.padding(16)
.backgroundColor(Color.White)
.borderRadius(16)
.onClick(() => {
this.showDeviceDetail(device);
})
}
4.6 辅助方法
typescript
// 获取当前房间的设备列表
private getFilteredDevices(): DeviceType[] {
if (this.currentRoom === '全部') {
return this.devices;
} else {
return this.devices.filter(device => device.room === this.currentRoom);
}
}
// 切换设备状态
private toggleDevice(deviceId: number, status: boolean): void {
const index = this.devices.findIndex(device => device.id === deviceId);
if (index !== -1) {
this.devices[index].status = status;
}
}
// 更新设备值
private updateDeviceValue(deviceId: number, value: number): void {
const index = this.devices.findIndex(device => device.id === deviceId);
if (index !== -1) {
this.devices[index].value = value;
}
}
// 获取设备状态文本
private getDeviceStatusText(device: DeviceType): string {
if (!device.status) {
return '已关闭';
}
switch (device.type) {
case 'light':
return `亮度 ${device.value}%`;
case 'ac':
return `温度 ${device.value}°C`;
case 'curtain':
return `开启度 ${device.value}%`;
case 'fridge':
return `温度 ${device.value}°C`;
case 'water_heater':
return `温度 ${device.value}°C`;
default:
return '已开启';
}
}
// 显示设备详情
private showDeviceDetail(device: DeviceType): void {
// 在实际应用中,这里会跳转到设备详情页面
console.info(`显示设备详情:${device.name}`);
}
5. GridRow和GridCol配置详解
在本案例中,我们使用了GridRow和GridCol组件实现网格布局。下面详细解析其配置:
5.1 GridRow配置
typescript
GridRow({
columns: { xs: 2, sm: 2, md: 3, lg: 4 },
gutter: { x: 16, y: 16 }
})
-
columns
:定义不同屏幕尺寸下的列数xs: 2
:极小屏幕(如小型手机)显示2列sm: 2
:小屏幕(如大型手机)显示2列md: 3
:中等屏幕(如平板)显示3列lg: 4
:大屏幕(如桌面)显示4列
-
gutter
:定义网格间的间距x: 16
:水平间距为16像素y: 16
:垂直间距为16像素
5.2 GridCol配置
在本案例中,我们使用了默认的GridCol配置,没有指定span属性,这意味着每个设备卡片占据一个网格单元。
typescript
GridCol() {
this.DeviceCard(device)
}
如果需要某些设备卡片占据更多的空间,可以通过span属性进行配置:
typescript
GridCol({
span: { xs: 2, sm: 1, md: 1, lg: 1 }
}) {
this.DeviceCard(device)
}
这样配置后,在极小屏幕(xs)上,该设备卡片会占据2列,而在其他屏幕尺寸上占据1列。
6. 布局效果分析
6.1 响应式布局
通过GridRow的columns配置,我们实现了响应式布局,使应用能够适应不同屏幕尺寸的设备:
屏幕尺寸 | 列数 | 效果 |
---|---|---|
极小屏幕(xs) | 2列 | 每行显示2个设备卡片 |
小屏幕(sm) | 2列 | 每行显示2个设备卡片 |
中等屏幕(md) | 3列 | 每行显示3个设备卡片 |
大屏幕(lg) | 4列 | 每行显示4个设备卡片 |
6.2 网格间距
通过GridRow的gutter配置,我们设置了网格间的间距为16像素,使布局更加美观、清晰。
6.3 设备卡片设计
我们设计的设备卡片包含以下元素:
- 设备图标和开关:显示设备类型和当前状态,用户可以直接切换设备的开关状态
- 设备名称:清晰地显示设备的名称
- 设备状态文本:显示设备的当前状态,如亮度、温度等
- 设备控制组件:根据设备类型显示不同的控制组件,如灯光的亮度滑块、空调的温度控制按钮等
这种设计使用户能够快速了解设备状态,并进行简单的控制操作。
7. GridRow和GridCol组件详解
7.1 GridRow组件
GridRow是HarmonyOS NEXT提供的网格行容器组件,用于创建网格布局。它具有以下主要属性:
属性 | 类型 | 描述 |
---|---|---|
columns | number | { xs?: number, sm?: number, md?: number, lg?: number, xl?: number, xxl?: number } | 当前行的总列数 |
gutter | number | { x?: number, y?: number } | 栅格间隔 |
breakpoints | { value: number, reference: BreakpointsReference }[] | 自定义断点值 |
7.2 GridCol组件
GridCol是HarmonyOS NEXT提供的网格列容器组件,用于在GridRow中创建网格列。它具有以下主要属性:
属性 | 类型 | 描述 |
---|---|---|
span | number | { xs?: number, sm?: number, md?: number, lg?: number, xl?: number, xxl?: number } | 列宽度 |
offset | number | { xs?: number, sm?: number, md?: number, lg?: number, xl?: number, xxl?: number } | 列偏移量 |
order | number | { xs?: number, sm?: number, md?: number, lg?: number, xl?: number, xxl?: number } | 列顺序 |
8. 完整代码
typescript
@Entry
@Component
struct SmartHomeGrid {
// 智能设备类型
interface DeviceType {
id: number; // 设备ID
name: string; // 设备名称
icon: Resource; // 设备图标
type: string; // 设备类型
room: string; // 所在房间
status: boolean; // 设备状态(开/关)
value?: number; // 设备值(如亮度、温度等)
color?: string; // 设备颜色(如灯光颜色)
}
// 房间类型
interface RoomType {
id: number; // 房间ID
name: string; // 房间名称
icon: Resource; // 房间图标
deviceCount: number; // 设备数量
}
// 房间数据
private rooms: RoomType[] = [
{
id: 1,
name: '客厅',
icon: $r('app.media.ic_living_room'),
deviceCount: 5
},
{
id: 2,
name: '卧室',
icon: $r('app.media.ic_bedroom'),
deviceCount: 3
},
{
id: 3,
name: '厨房',
icon: $r('app.media.ic_kitchen'),
deviceCount: 4
},
{
id: 4,
name: '浴室',
icon: $r('app.media.ic_bathroom'),
deviceCount: 2
},
{
id: 5,
name: '书房',
icon: $r('app.media.ic_study'),
deviceCount: 3
}
];
// 智能设备数据
@State devices: DeviceType[] = [
{
id: 1,
name: '客厅灯',
icon: $r('app.media.ic_light'),
type: 'light',
room: '客厅',
status: true,
value: 80,
color: '#FFD700'
},
{
id: 2,
name: '空调',
icon: $r('app.media.ic_ac'),
type: 'ac',
room: '客厅',
status: true,
value: 24
},
{
id: 3,
name: '电视',
icon: $r('app.media.ic_tv'),
type: 'tv',
room: '客厅',
status: false
},
{
id: 4,
name: '窗帘',
icon: $r('app.media.ic_curtain'),
type: 'curtain',
room: '客厅',
status: true,
value: 100
},
{
id: 5,
name: '音响',
icon: $r('app.media.ic_speaker'),
type: 'speaker',
room: '客厅',
status: false
},
{
id: 6,
name: '卧室灯',
icon: $r('app.media.ic_light'),
type: 'light',
room: '卧室',
status: false,
value: 0,
color: '#FFFFFF'
},
{
id: 7,
name: '床头灯',
icon: $r('app.media.ic_bedside_lamp'),
type: 'light',
room: '卧室',
status: true,
value: 30,
color: '#FFA07A'
},
{
id: 8,
name: '卧室空调',
icon: $r('app.media.ic_ac'),
type: 'ac',
room: '卧室',
status: true,
value: 26
},
{
id: 9,
name: '厨房灯',
icon: $r('app.media.ic_light'),
type: 'light',
room: '厨房',
status: false,
value: 0,
color: '#FFFFFF'
},
{
id: 10,
name: '冰箱',
icon: $r('app.media.ic_fridge'),
type: 'fridge',
room: '厨房',
status: true,
value: 4
},
{
id: 11,
name: '烤箱',
icon: $r('app.media.ic_oven'),
type: 'oven',
room: '厨房',
status: false
},
{
id: 12,
name: '洗碗机',
icon: $r('app.media.ic_dishwasher'),
type: 'dishwasher',
room: '厨房',
status: false
},
{
id: 13,
name: '浴室灯',
icon: $r('app.media.ic_light'),
type: 'light',
room: '浴室',
status: false,
value: 0,
color: '#FFFFFF'
},
{
id: 14,
name: '热水器',
icon: $r('app.media.ic_water_heater'),
type: 'water_heater',
room: '浴室',
status: true,
value: 45
},
{
id: 15,
name: '书房灯',
icon: $r('app.media.ic_light'),
type: 'light',
room: '书房',
status: true,
value: 70,
color: '#F5F5DC'
},
{
id: 16,
name: '台灯',
icon: $r('app.media.ic_desk_lamp'),
type: 'light',
room: '书房',
status: true,
value: 50,
color: '#F0E68C'
},
{
id: 17,
name: '书房空调',
icon: $r('app.media.ic_ac'),
type: 'ac',
room: '书房',
status: false,
value: 0
}
];
@State currentRoom: string = '全部';
build() {
Column() {
// 顶部状态栏
this.StatusBar()
// 房间选择栏
this.RoomSelector()
// 设备网格列表
this.DeviceGrid()
}
.width('100%')
.height('100%')
.backgroundColor('#F5F5F5')
}
@Builder
private StatusBar() {
Row() {
Column() {
Text('智能家居')
.fontSize(20)
.fontWeight(FontWeight.Bold)
.fontColor('#333333')
Text('欢迎回家,张先生')
.fontSize(14)
.fontColor('#666666')
.margin({ top: 4 })
}
.alignItems(HorizontalAlign.Start)
Blank()
Row() {
// 添加设备按钮
Button({ type: ButtonType.Circle }) {
Image($r('app.media.ic_add'))
.width(24)
.height(24)
}
.width(40)
.height(40)
.backgroundColor('#EEEEEE')
.margin({ right: 12 })
// 设置按钮
Button({ type: ButtonType.Circle }) {
Image($r('app.media.ic_settings'))
.width(24)
.height(24)
}
.width(40)
.height(40)
.backgroundColor('#EEEEEE')
}
}
.width('100%')
.padding({ left: 16, right: 16, top: 16, bottom: 16 })
.backgroundColor(Color.White)
}
@Builder
private RoomSelector() {
Scroll(ScrollDirection.Horizontal) {
Row() {
// 全部选项
Column() {
Image($r('app.media.ic_all_rooms'))
.width(40)
.height(40)
.margin({ bottom: 8 })
Text('全部')
.fontSize(14)
.fontColor(this.currentRoom === '全部' ? '#4285F4' : '#666666')
.fontWeight(this.currentRoom === '全部' ? FontWeight.Bold : FontWeight.Normal)
}
.width(80)
.height(80)
.padding(8)
.margin({ right: 12 })
.borderRadius(12)
.backgroundColor(this.currentRoom === '全部' ? '#E8F0FE' : Color.White)
.onClick(() => {
this.currentRoom = '全部';
})
// 各个房间选项
ForEach(this.rooms, (room: RoomType) => {
Column() {
Image(room.icon)
.width(40)
.height(40)
.margin({ bottom: 8 })
Text(room.name)
.fontSize(14)
.fontColor(this.currentRoom === room.name ? '#4285F4' : '#666666')
.fontWeight(this.currentRoom === room.name ? FontWeight.Bold : FontWeight.Normal)
}
.width(80)
.height(80)
.padding(8)
.margin({ right: 12 })
.borderRadius(12)
.backgroundColor(this.currentRoom === room.name ? '#E8F0FE' : Color.White)
.onClick(() => {
this.currentRoom = room.name;
})
})
}
.padding({ left: 16, right: 16 })
}
.scrollBar(BarState.Off)
.width('100%')
.margin({ top: 16, bottom: 16 })
}
@Builder
private DeviceGrid() {
Column() {
// 标题栏
Row() {
Text(this.currentRoom === '全部' ? '所有设备' : `${this.currentRoom}设备`)
.fontSize(18)
.fontWeight(FontWeight.Bold)
.fontColor('#333333')
Blank()
Text(`${this.getFilteredDevices().length}个设备`)
.fontSize(14)
.fontColor('#666666')
}
.width('100%')
.padding({ left: 16, right: 16, bottom: 12 })
// 使用GridRow和GridCol实现网格布局
Scroll() {
GridRow({
columns: { xs: 2, sm: 2, md: 3, lg: 4 },
gutter: { x: 16, y: 16 }
}) {
ForEach(this.getFilteredDevices(), (device: DeviceType) => {
GridCol() {
this.DeviceCard(device)
}
})
}
.width('100%')
.padding(16)
}
.scrollBar(BarState.Off)
.scrollable(ScrollDirection.Vertical)
.width('100%')
.layoutWeight(1)
}
.width('100%')
.layoutWeight(1)
.backgroundColor('#F5F5F5')
.borderRadius({ topLeft: 24, topRight: 24 })
}
@Builder
private DeviceCard(device: DeviceType) {
Column() {
// 设备图标和状态
Row() {
Image(device.icon)
.width(24)
.height(24)
.fillColor(device.status ? '#4285F4' : '#999999')
Blank()
Toggle({ type: ToggleType.Switch, isOn: device.status })
.width(40)
.height(24)
.selectedColor('#4285F4')
.onChange((isOn: boolean) => {
this.toggleDevice(device.id, isOn);
})
}
.width('100%')
// 设备名称
Text(device.name)
.fontSize(16)
.fontWeight(FontWeight.Medium)
.fontColor('#333333')
.margin({ top: 12 })
// 设备状态文本
Text(this.getDeviceStatusText(device))
.fontSize(14)
.fontColor('#666666')
.margin({ top: 4 })
// 设备控制组件(根据设备类型显示不同控制)
if (device.type === 'light' && device.status) {
// 灯光亮度控制
Column() {
Row() {
Image($r('app.media.ic_brightness'))
.width(16)
.height(16)
.margin({ right: 8 })
Text('亮度')
.fontSize(14)
.fontColor('#666666')
Blank()
Text(`${device.value}%`)
.fontSize(14)
.fontColor('#4285F4')
}
.width('100%')
.margin({ top: 12 })
Slider({
value: device.value,
min: 0,
max: 100,
step: 1,
style: SliderStyle.OutSet
})
.width('100%')
.margin({ top: 8 })
.selectedColor('#4285F4')
.onChange((value: number) => {
this.updateDeviceValue(device.id, value);
})
}
.width('100%')
} else if (device.type === 'ac' && device.status) {
// 空调温度控制
Row() {
Button('-')
.width(32)
.height(32)
.fontSize(16)
.fontColor('#666666')
.backgroundColor('#EEEEEE')
.borderRadius(16)
.onClick(() => {
if (device.value > 16) {
this.updateDeviceValue(device.id, device.value - 1);
}
})
Text(`${device.value}°C`)
.fontSize(16)
.fontColor('#4285F4')
.fontWeight(FontWeight.Bold)
.margin({ left: 12, right: 12 })
Button('+')
.width(32)
.height(32)
.fontSize(16)
.fontColor('#666666')
.backgroundColor('#EEEEEE')
.borderRadius(16)
.onClick(() => {
if (device.value < 30) {
this.updateDeviceValue(device.id, device.value + 1);
}
})
}
.width('100%')
.margin({ top: 12 })
.justifyContent(FlexAlign.Center)
}
}
.width('100%')
.padding(16)
.backgroundColor(Color.White)
.borderRadius(16)
.onClick(() => {
this.showDeviceDetail(device);
})
}
// 获取当前房间的设备列表
private getFilteredDevices(): DeviceType[] {
if (this.currentRoom === '全部') {
return this.devices;
} else {
return this.devices.filter(device => device.room === this.currentRoom);
}
}
// 切换设备状态
private toggleDevice(deviceId: number, status: boolean): void {
const index = this.devices.findIndex(device => device.id === deviceId);
if (index !== -1) {
this.devices[index].status = status;
}
}
// 更新设备值
private updateDeviceValue(deviceId: number, value: number): void {
const index = this.devices.findIndex(device => device.id === deviceId);
if (index !== -1) {
this.devices[index].value = value;
}
}
// 获取设备状态文本
private getDeviceStatusText(device: DeviceType): string {
if (!device.status) {
return '已关闭';
}
switch (device.type) {
case 'light':
return `亮度 ${device.value}%`;
case 'ac':
return `温度 ${device.value}°C`;
case 'curtain':
return `开启度 ${device.value}%`;
case 'fridge':
return `温度 ${device.value}°C`;
case 'water_heater':
return `温度 ${device.value}°C`;
default:
return '已开启';
}
}
// 显示设备详情
private showDeviceDetail(device: DeviceType): void {
// 在实际应用中,这里会跳转到设备详情页面
console.info(`显示设备详情:${device.name}`);
}
}
9. 总结
本教程详细讲解了如何使用HarmonyOS NEXT中的GridRow和GridCol组件实现智能家居控制面板的网格布局。通过合理的数据结构设计、精心的UI设计和灵活的GridRow配置,我们实现了一个美观、响应式的智能家居控制面板。
主要内容包括:
- 智能设备数据结构设计和数据准备
- 整体布局实现,包括顶部状态栏、房间选择栏和设备网格列表
- GridRow和GridCol组件的配置和使用
- 设备卡片的设计和实现,包括不同类型设备的控制组件
- 布局效果分析