【HarmonyOS】定义一个三段式插槽设计的TitleBar组件

前言

本文章适合看完Harmony官方教程,或者具有一定的前端知识的读者。

基于三段式插槽设计的TitleBar组件

使用插槽设计会让组件变得更加灵活,开发者可以自行配置的预制子元素,也可以按照自己的意愿来定制槽位区域。

如何实现

常见的TitleBar标题居中,左侧返回或者菜单,右侧一到二个按钮。实现的方式很多种,我选择层叠布局(Stack)和弹性布局(Flex)来实现,代码如下:

scss 复制代码
build() {
    Stack() {
      this.content()  //中间槽位
      Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) {
        this.navigation()  //左侧槽位
        this.actions()  //右侧槽位
      }
    }
  }

通过@BuilderParam装饰器引用@Builder函数,实现插槽和预制子元素

@BuilderParam用来装饰指向@Builder方法的变量,开发者可在初始化自定义组件时对此属性进行赋值,为自定义组件增加特定的功能。 该装饰器用于声明任意UI描述的一个元素,类似slot占位符。 代码如下:

kotlin 复制代码
  @Builder navigationBuilder() {
    Image(this.navigationSrc)
      .width(this.iconWidth)
      .height(this.iconHeight)
      .objectFit(this.iconFit)
      .margin(this.navigationMargin)
      .onClick(() => {
        this.navigationCallback?.()
      })
  }

  @Builder contentBuilder() {
    Text(this.contentText)
      .fontColor(this.contentFontColor)
      .fontSize(this.contentFontSize)
  }

  @Builder actionsBuilder() {
    Row({ space: this.actionSpace }) {
      ForEach(this.actionAttribute, (item: ActionAttribute) => {
        Image(item.src)
          .width(this.iconWidth)
          .height(this.iconHeight)
          .objectFit(this.iconFit)
          .onClick(() => {
            item.callback?.()
          })
      })
    }
    .justifyContent(this.actionAlign)
    .margin(this.actionMargin)
  }

  @BuilderParam navigation: () => void = this.navigationBuilder
  @BuilderParam content: () => void = this.contentBuilder
  @BuilderParam actions: () => void = this.actionsBuilder

效果图

完整代码

kotlin 复制代码
@Component
export default struct TitleBar {
  iconWidth: Length = 25
  iconHeight: Length = 25
  iconFit: ImageFit = ImageFit.Contain
  navigationMargin: Margin | Length = 15
  navigationAlignment: Alignment = Alignment.Start
  navigationSrc: string | PixelMap | Resource = $r("app.media.arrow_left")
  navigationCallback?: () => void = null;
  contentAlignment: Alignment = Alignment.Center
  contentText: string = "";
  contentFontColor: ResourceColor = Color.Black
  contentFontSize: number | string | Resource = 18
  actionMargin: Margin | Length = 15
  actionSpace: string | number = 15
  actionAlign: FlexAlign = FlexAlign.End
  actionAttribute?: Array<ActionAttribute> = null

  @Builder navigationBuilder() {
    Image(this.navigationSrc)
      .width(this.iconWidth)
      .height(this.iconHeight)
      .objectFit(this.iconFit)
      .margin(this.navigationMargin)
      .onClick(() => {
        this.navigationCallback?.()
      })
  }

  @Builder contentBuilder() {
    Text(this.contentText)
      .fontColor(this.contentFontColor)
      .fontSize(this.contentFontSize)
  }

  @Builder actionsBuilder() {
    Row({ space: this.actionSpace }) {
      ForEach(this.actionAttribute, (item: ActionAttribute) => {
        Image(item.src)
          .width(this.iconWidth)
          .height(this.iconHeight)
          .objectFit(this.iconFit)
          .onClick(() => {
            item.callback?.()
          })
      })
    }
    .justifyContent(this.actionAlign)
    .margin(this.actionMargin)
  }

  @BuilderParam navigation: () => void = this.navigationBuilder
  @BuilderParam content: () => void = this.contentBuilder
  @BuilderParam actions: () => void = this.actionsBuilder

  build() {
    Stack() {
      this.content()
      Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) {
        this.navigation()
        this.actions()
      }
    }
  }
}

class ActionAttribute {
  public src: string | PixelMap | Resource = $r("app.media.icon")
  public callback?: () => void = null;
}

如何使用

scss 复制代码
@Entry
@Component
struct TitleBarPage {
  build() {
    Column({ space: 15 }) {
      TitleBar({
        navigationCallback: () => {
          console.log('导航按钮回调')
        },
        contentText: '默认TitleBar'
      })
        .backgroundColor('#F1F3F5')

      TitleBar({
        navigationSrc: $r("app.media.menu"),
        navigationCallback: () => {
          console.log('导航按钮回调')
        },
        contentText: '更改导航按钮'
      })
        .backgroundColor('#F1F3F5')

      TitleBar({
        navigationCallback: () => {
          console.log('导航按钮回调')
        },
        contentText: '添加活动按钮',
        actionAttribute: [
          {
            src: $r('app.media.browser'),
            callback: () => {
              console.log('活动按钮回调')
            }
          },
          {
            src: $r('app.media.more'),
            callback: () => {
              console.log('活动按钮回调')
            }
          }
        ]
      })
        .backgroundColor('#F1F3F5')

      TitleBar({
        navigationCallback: () => {
          console.log('导航按钮回调')
        },
        content: this.contentBuilder
      })
        .backgroundColor('#F1F3F5')
    }
    .width('100%')
    .height(50)
    .justifyContent(FlexAlign.Center)
  }

  @Builder contentBuilder() {
    Row({ space: 5 }) {
      Text('替换标题插槽')
        .fontColor(Color.Black)
        .fontSize(18)
      Image($r('app.media.arrow_down'))
        .width(15)
        .height(15)
        .objectFit(ImageFit.Contain)
    }
    .onClick(() => {
      console.log('替换标题插槽')
    })
  }
}

Thanks

以上就是本篇文章的全部内容,如有问题欢迎指出,我们一起进步。

如果觉得本篇文章对您有帮助的话请点个赞让更多人看到吧,您的鼓励是我前进的动力。

谢谢~~

相关推荐
HarmonyOS_SDK5 分钟前
汽车之家联合HarmonyOS SDK,深度构建鸿蒙生态体系
harmonyos
whysqwhw5 分钟前
鸿蒙沉浸式
harmonyos
autumnTop6 分钟前
为什么访问不了同事的服务器或者ping不通地址了?
前端·后端·程序员
weixin_4433533128 分钟前
小红书帖子评论的nodejs爬虫脚本
前端·爬虫
yzzzzzzzzzzzzzzzzz29 分钟前
HTML 常用标签介绍
前端·html
Wcy307651906632 分钟前
web前端第二次作业
前端·javascript·css
北京_宏哥33 分钟前
Python零基础从入门到精通详细教程11 - python数据类型之数字(Number)-浮点型(float)详解
前端·python·面试
waterHBO35 分钟前
css 模拟一个动画效果,消息堆叠。
前端·css
艾小码1 小时前
JavaScript 排序完全指南:从基础到高阶实战
前端·javascript·排序算法
前端加油站1 小时前
在 cursor 成为流行的开发方式后,作为普通开发我们能做什么
前端