前言
本文章适合看完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
以上就是本篇文章的全部内容,如有问题欢迎指出,我们一起进步。
如果觉得本篇文章对您有帮助的话请点个赞让更多人看到吧,您的鼓励是我前进的动力。
谢谢~~