【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

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

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

谢谢~~

相关推荐
安冬的码畜日常9 分钟前
【D3.js in Action 3 精译_027】3.4 让 D3 数据适应屏幕(下)—— D3 分段比例尺的用法
前端·javascript·信息可视化·数据可视化·d3.js·d3比例尺·分段比例尺
l1x1n036 分钟前
No.3 笔记 | Web安全基础:Web1.0 - 3.0 发展史
前端·http·html
昨天;明天。今天。1 小时前
案例-任务清单
前端·javascript·css
GEEKVIP2 小时前
手机使用技巧:8 个 Android 锁屏移除工具 [解锁 Android]
android·macos·ios·智能手机·电脑·手机·iphone
zqx_72 小时前
随记 前端框架React的初步认识
前端·react.js·前端框架
惜.己2 小时前
javaScript基础(8个案例+代码+效果图)
开发语言·前端·javascript·vscode·css3·html5
什么鬼昵称3 小时前
Pikachu-csrf-CSRF(get)
前端·csrf
长天一色3 小时前
【ECMAScript 从入门到进阶教程】第三部分:高级主题(高级函数与范式,元编程,正则表达式,性能优化)
服务器·开发语言·前端·javascript·性能优化·ecmascript
NiNg_1_2343 小时前
npm、yarn、pnpm之间的区别
前端·npm·node.js
秋殇与星河3 小时前
CSS总结
前端·css