玩转HarmonyOS NEXT之IM应用首页布局

本文从目前流行的垂类市场中,选择即时通讯应用作为典型案例详细介绍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’,这可能表示屏幕宽度的断点。

布局和结构

  • GridRowGridCol:表示一个栅格布局,GridRow 包含一行,GridCol 表示该行中的一列。
  • columns: 1span: 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布局

构建了一个包含底部导航栏的界面布局。使用TabsTabContent组件来构建一个带有多个标签页的布局,每个标签页都通过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]):扩展安全区域到底部,确保内容不会被系统导航栏遮挡。

实现效果图

在这里插入图片描述

参考文章

  • 12
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全栈探索者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值