本文从目前流行的垂类市场中,选择即时通讯应用作为典型案例详细介绍HarmonyOS NEXT
的各类布局在实际开发中的综合应用。即时通讯应用的核心功能为用户交互,主要包含对话聊天、通讯录,社交圈等交互功能。
应用首页
创建一个包含一列的栅格布局,显示文本“首页”,并且监听断点变化,当断点发生变化时更新 currentBreakpoint
状态。
- 示例代码
@Entry @Component struct Index { @StorageLink('currentBreakpoint') currentBreakpoint: string = 'sm'; build() { GridRow({ columns: 1 }) { GridCol({ span: 1 } ) { Column() { Text('首页') } .width('100%') .height('100%') } } .onBreakpointChange((breakPoint => { this.currentBreakpoint = breakPoint; })) } }
装饰器
@Entry
:标记这是一个页面入口@Component
:标记这是一个组件
状态管理
@StorageLink
:全局UI状态存储。currentBreakpoint
:声明并初始化了一个字符串类型的状态变量,初始值为 ‘sm’,这可能表示屏幕宽度的断点。
布局和结构
GridRow
和GridCol
:表示一个栅格布局,GridRow
包含一行,GridCol
表示该行中的一列。columns: 1
和span: 1
:指定网格布局中的列数和列的跨度。
断点变化处理
.onBreakpointChange
:绑定一个事件处理函数,当断点变化时触发。(breakPoint => { this.currentBreakpoint = breakPoint; })
:定义了一个箭头函数,将新的断点值赋给currentBreakpoint
。
HomeTab组件
BottomNavigation构造器
BottomNavigation
构建器函数用于创建一个带有图像和文本的底部导航按钮,具有自适应布局和状态变化的功能。通过点击按钮,可以更新当前页面索引,从而改变按钮的显示状态(例如图像和文本的颜色)。
- 示例代码
interface BottomNavigationProps {
index: number;
img: Resource;
selectImg?: Resource;
title: Resource | string;
}
@Builder
BottomNavigation(button: BottomNavigationProps) {
Column() {
Image(this.currentPageIndex === button.index ? button.selectImg : button.img)
.objectFit(ImageFit.Contain)
.width(this.currentBreakpoint === 'lg' ? '24vp' : '22vp')
.height(this.currentBreakpoint === 'lg' ? '24vp' : '22vp')
Text(button.title)
.fontColor(this.currentPageIndex === button.index ? '#0A59F7' : Color.Black)
.opacity(this.currentPageIndex === button.index ? 1 : 0.6)
.fontWeight(500)
.textAlign(TextAlign.Center)
.fontSize('10fp')
.lineHeight('14vp')
.fontFamily('HarmonyHeiTi-Bold')
.margin({ top: '4vp' })
}
.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Center)
.onClick(() => {
this.currentPageIndex = button.index;
})
}
}
参数类型约束
interface BottomNavigationProps {
index: number;
img: Resource;
selectImg?: Resource;
title: Resource | string;
}
index
:按钮的索引,用于标识按钮。img
:按钮的默认图像资源。selectImg
:按钮的选中状态图像资源(可选)。title
:按钮的标题,可以是资源或字符串。
构造器函数
@Builder
BottomNavigation(button: BottomNavigationProps) {
@Builder
:表示这是一个构建器函数,用于构建UI组件。BottomNavigation(button: BottomNavigationProps)
:定义了接收一个 BottomNavigationProps 类型的参数 button。
组件布局
Column() {
Image(this.currentPageIndex === button.index ? button.selectImg : button.img)
.objectFit(ImageFit.Contain)
.width(this.currentBreakpoint === 'lg' ? '24vp' : '22vp')
.height(this.currentBreakpoint === 'lg' ? '24vp' : '22vp')
Column()
:创建一个列布局,用于垂直排列组件。Image(...)
:根据当前页面索引和按钮索引是否匹配来选择显示按钮的图像或选中状态的图像。objectFit(ImageFit.Contain)
:设置图像的适应方式为“Contain”。.width(...) 和 .height(...)
:根据断点调整图像的宽度和高度。
文本设置
Text(button.title)
.fontColor(this.currentPageIndex === button.index ? '#0A59F7' : Color.Black)
.opacity(this.currentPageIndex === button.index ? 1 : 0.6)
.fontWeight(500)
.textAlign(TextAlign.Center)
.fontSize('10fp')
.lineHeight('14vp')
.fontFamily('HarmonyHeiTi-Bold')
.margin({ top: '4vp' })
Text(button.title)
:显示按钮的标题。.fontColor(...)
:根据按钮是否被选中设置字体颜色。.opacity(...)
:根据按钮是否被选中设置透明度。.fontWeight(500)
:设置字体粗细。.textAlign(TextAlign.Center)
:设置文本对齐方式为居中。.fontSize('10fp') 和 .lineHeight('14vp')
:设置字体大小和行高。.fontFamily('HarmonyHeiTi-Bold')
:设置字体样式。margin({ top: '4vp' })
:设置顶部外边距。
列对齐和点击事件
.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Center)
.onClick(() => {
this.currentPageIndex = button.index;
})
.alignItems(HorizontalAlign.Center)
:设置列交叉轴居中对齐。.justifyContent(FlexAlign.Center)
:设置列主轴居中对齐。.onClick(...)
:绑定点击事件处理函数,当按钮被点击时更新 currentPageIndex 为按钮的索引。
HomeTab布局
构建了一个包含底部导航栏的界面布局。使用Tabs
和TabContent
组件来构建一个带有多个标签页的布局,每个标签页都通过BottomNavigation
函数生成按钮,这些按钮包含图像和文本,并且具有自适应布局和状态变化的功能。通过点击标签页按钮,可以更新currentPageIndex
,从而改变当前显示的页面内容。
- 示例代码
interface BottomNavigationProps {
index: number;
img: Resource;
selectImg?: Resource;
title: Resource | string;
}
@Component
export default struct HomeTab {
@StorageProp('currentBreakpoint') currentBreakpoint: string = 'sm';
@Link currentPageIndex: number;
build() {
Column() {
Tabs({ barPosition: this.currentBreakpoint === 'lg' ? BarPosition.Start : BarPosition.End }) {
TabContent()
.tabBar(this.BottomNavigation({
index: 0,
img: $r('app.media.icon_message'),
selectImg: $r('app.media.icon_message_selected'),
title: '消息'
}))
TabContent()
.tabBar(this.BottomNavigation({
index: 1,
img: $r('app.media.icon_contacts'),
selectImg: $r('app.media.icon_contacts_selected'),
title: '通讯录'
}))
TabContent()
.tabBar(this.BottomNavigation({
index: 2,
img: $r("app.media.icon_social_circle"),
selectImg: $r("app.media.icon_social_circle_selected"),
title: '朋友圈'
}))
TabContent()
.tabBar(this.BottomNavigation({
index: 3,
img: $r('app.media.icon_me'),
selectImg: $r('app.media.icon_me'),
title: '我的'
}))
}
.vertical(this.currentBreakpoint === 'lg')
.height('100%')
.margin({
top: this.currentBreakpoint === 'lg' ? '' : '6.5vp',
bottom: this.currentBreakpoint === 'lg' ? '' : '7.5vp'
})
}
.backgroundColor('#F1F3F5')
.expandSafeArea([], [SafeAreaEdge.BOTTOM])
}
@Builder
BottomNavigation(button: BottomNavigationProps) {
Column() {
Image(this.currentPageIndex === button.index ? button.selectImg : button.img)
.objectFit(ImageFit.Contain)
.width(this.currentBreakpoint === 'lg' ? '24vp' : '22vp')
.height(this.currentBreakpoint === 'lg' ? '24vp' : '22vp')
Text(button.title)
.fontColor(this.currentPageIndex === button.index ? '#0A59F7' : Color.Black)
.opacity(this.currentPageIndex === button.index ? 1 : 0.6)
.fontWeight(500)
.textAlign(TextAlign.Center)
.fontSize('10fp')
.lineHeight('14vp')
.fontFamily('HarmonyHeiTi-Bold')
.margin({ top: '4vp' })
}
.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Center)
.onClick(() => {
this.currentPageIndex = button.index;
})
}
}
Link状态存储
@Link currentPageIndex: number;
@Link
:标记currentPageIndex
为一个Link状态变量,子组件中被@Link
装饰的变量与其父组件中对应的数据源建立双向数据绑定。currentPageIndex
:当前页面的索引。
标签页
Tabs({ barPosition: this.currentBreakpoint === 'lg' ? BarPosition.Start : BarPosition.End }) {
Tabs
:创建一个标签页组件。barPosition
:根据当前断点设置标签栏的位置,如果断点为lg
,则标签栏位置为Start
,否则为End
。
安全区域
.backgroundColor('#F1F3F5')
.expandSafeArea([], [SafeAreaEdge.BOTTOM])
.expandSafeArea([], [SafeAreaEdge.BOTTOM])
:扩展安全区域到底部,确保内容不会被系统导航栏遮挡。
实现效果图
参考文章
- 栅格布局
- 线性布局
- 全局状态存储