【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

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

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

谢谢~~

相关推荐
hackeroink37 分钟前
【2024版】最新推荐好用的XSS漏洞扫描利用工具_xss扫描工具
前端·xss
迷雾漫步者2 小时前
Flutter组件————FloatingActionButton
前端·flutter·dart
SoraLuna3 小时前
「Mac畅玩鸿蒙与硬件47」UI互动应用篇24 - 虚拟音乐控制台
开发语言·macos·ui·华为·harmonyos
向前看-3 小时前
验证码机制
前端·后端
燃先生._.4 小时前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js
拭心4 小时前
Google 提供的 Android 端上大模型组件:MediaPipe LLM 介绍
android
高山我梦口香糖5 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
m0_748235245 小时前
前端实现获取后端返回的文件流并下载
前端·状态模式
m0_748240255 小时前
前端如何检测用户登录状态是否过期
前端