鸿蒙应用开发-组件构建函数

自定义构建函数

1. 构建函数-@Builder

ArkUI还提供了一种更轻量的UI元素复用机制 @Builder ,可以将重复使用的UI元素抽象成一个方法,在 build 方法里调用。

  • 组件内定义
  • 全局定义

1)组件内定义

java 复制代码
@Builder MyBuilderFunction() {}
java 复制代码
this.MyBuilderFunction()

2)全局定义

java 复制代码
@Builder function MyGlobalBuilderFunction() {}
java 复制代码
MyGlobalBuilderFunction()

📕📕📕 练习案例→商品详情-更多按钮

java 复制代码
@Entry
@Component
struct Index {
  build() {
    Column() {
      GridRow({ columns: 2, gutter: 15 }) {
        GridCol({ span: 2 }) {
          Column() {
            Row() {
              Text('评价(2000+)')
                .layoutWeight(1)
                .fontWeight(600)
              // TODO
            }
            .padding(10)

            Row()
              .height(100)
          }
          .borderRadius(12)
          .backgroundColor('#fff')
        }

        GridCol() {
          Column() {
            Row() {
              Text('推荐')
                .layoutWeight(1)
                .fontWeight(600)
              // TODO
            }
            .padding(10)

            Row()
              .height(100)
          }
          .borderRadius(12)
          .backgroundColor('#fff')
        }

        GridCol() {
          Column() {
            Row() {
              Text('体验')
                .layoutWeight(1)
                .fontWeight(600)
              // TODO
            }
            .padding(10)

            Row()
              .height(100)
          }
          .borderRadius(12)
          .backgroundColor('#fff')
        }
      }
    }
    .height('100%')
    .padding(15)
    .backgroundColor('#f5f5f5')
  }
}

使用 @Builder 提取UI结构

java 复制代码
@Entry
@Component
struct Index {

  @Builder
  MoreBuilder () {
    Row() {
      Text('查看更多')
        .fontSize(14)
        .fontColor('#666666')
      Image($r('app.media.ic_public_arrow_right'))
        .width(16)
        .fillColor('#666666')
    }
  }

  build() {
    Column() {
      GridRow({ columns: 2, gutter: 15 }) {
        GridCol({ span: 2 }) {
          Column() {
            Row() {
              Text('评价(2000+)')
                .layoutWeight(1)
                .fontWeight(600)
              this.MoreBuilder()
            }
            .padding(10)

            Row()
              .height(100)
          }
          .borderRadius(12)
          .backgroundColor('#fff')
        }

        GridCol() {
          Column() {
            Row() {
              Text('推荐')
                .layoutWeight(1)
                .fontWeight(600)
              this.MoreBuilder()
            }
            .padding(10)

            Row()
              .height(100)
          }
          .borderRadius(12)
          .backgroundColor('#fff')
        }

        GridCol() {
          Column() {
            Row() {
              Text('体验')
                .layoutWeight(1)
                .fontWeight(600)
              this.MoreBuilder()
            }
            .padding(10)

            Row()
              .height(100)
          }
          .borderRadius(12)
          .backgroundColor('#fff')
        }
      }
    }
    .height('100%')
    .padding(15)
    .backgroundColor('#f5f5f5')
  }
}

小结:

  • 遇到非遍历情况下,一个组件分散着相同的UI结构,可以使用 @Builder 更轻量

    其他:

  • GridRow GridCol 栅格布局

2. 构建函数-传参传递

1)按值传递(场景:构建不同的UI)

java 复制代码
@Builder MyBuilderFunction( title: string ) {}
java 复制代码
this.MyBuilderFunction('Title')

需求:不同板块查看更多文案不一样

  • 评价 好评率 98%

  • 推荐 查看全部

  • 体验 4 条测评

java 复制代码
@Builder
  MoreBuilder (title: string) {
    Row() {
      Text(title)
        .fontSize(14)
        .fontColor('#666666')
      Image($r('app.media.ic_public_arrow_right'))
        .width(16)
        .fillColor('#666666')
    }
  }
java 复制代码
this.MoreBuilder('好评率 98%')
this.MoreBuilder('查看全部')
this.MoreBuilder('4 条测评')

2)引用传递(场景:当传递的数据更新,需要更新UI)

需求:

  • 点击按钮后模拟加载好评率数据
java 复制代码
@Entry
@Component
struct Index {
  @State
  rate: number = 0

  @Builder
  MoreBuilder(params: { title: string }) {
    Row() {
      Text(params.title)
        .fontSize(14)
        .fontColor('#666666')
      Image($r('app.media.ic_public_arrow_right'))
        .width(16)
        .fillColor('#666666')
    }
  }

  build() {
    Column() {
      Button('获取数据')
        .margin({ bottom: 15 })
        .onClick(() => {
          this.rate = 99
        })
      GridRow({ columns: 2, gutter: 15 }) {
        GridCol({ span: 2 }) {
          Column() {
            Row() {
              Text('评价(2000+)')
                .layoutWeight(1)
                .fontWeight(600)
              this.MoreBuilder({ title: `好评率 ${this.rate} %` })
            }
            .padding(10)

            Row()
              .height(100)
          }
          .borderRadius(12)
          .backgroundColor('#fff')
        }

        GridCol() {
          Column() {
            Row() {
              Text('推荐')
                .layoutWeight(1)
                .fontWeight(600)
              this.MoreBuilder({ title: '查看全部' })
            }
            .padding(10)

            Row()
              .height(100)
          }
          .borderRadius(12)
          .backgroundColor('#fff')
        }

        GridCol() {
          Column() {
            Row() {
              Text('体验')
                .layoutWeight(1)
                .fontWeight(600)
              this.MoreBuilder({ title: '4 条测评' })
            }
            .padding(10)

            Row()
              .height(100)
          }
          .borderRadius(12)
          .backgroundColor('#fff')
        }
      }
    }
    .height('100%')
    .padding(15)
    .backgroundColor('#f5f5f5')
  }
}
  • 使用** @Builder** 复用逻辑的时候,支持传参可以更灵活的渲染UI
  • 参数可以使用状态数据,不过建议通过对象的方式传入 @Builder
  1. 构建函数-@BuilderParam 传递UI
    @BuilderParam 该装饰器用于声明任意UI描述的一个元素,类似 slot 占位符

前置知识

组件属性初始化:

  • 定义组件声明属性 title: string
  • 使用组件初始化属性 Comp({ title: string })
  • 尾随闭包初始化组件

    • 组件内有且仅有一个使用 @BuilderParam 装饰的属性
  • 参数初始化组件

    • 组件内有多个使用 @BuilderParam 装饰器属性

1)尾随闭包初始化组件(默认插槽)

需求:

  • 标题文字和更多文案通过属性传入

  • 内容结构需要传入

java 复制代码
@Component
struct PanelComp {
  title: string
  more: string
  @BuilderParam
  panelContent: () => void = this.DefaultPanelContent

  // 备用 Builder
  @Builder
  DefaultPanelContent () {
    Text('默认内容')
  }

  build() {
    Column() {
      Row() {
        Text(this.title)
          .layoutWeight(1)
          .fontWeight(600)
        Row() {
          Text(this.more)
            .fontSize(14)
            .fontColor('#666666')
          Image($r('app.media.ic_public_arrow_right'))
            .width(16)
            .fillColor('#666666')
        }
      }
      .padding(10)

      Row() {
        this.panelContent()
      }
      .height(100)
    }
    .borderRadius(12)
    .backgroundColor('#fff')
  }
}

@Entry
@Component
struct Index {
  build() {
    Column() {
      GridRow({ columns: 2, gutter: 15 }) {
        GridCol({ span: 2 }) {
          PanelComp({ title: '评价(2000+)', more: '好评率98%' })
        }

        GridCol() {
          PanelComp({ title: '推荐', more: '查看全部' }){
            Text('推荐内容')
          }
        }

        GridCol() {
          PanelComp({ title: '体验', more: '4 条测评' }){
            Text('体验内容')
          }
        }
      }
    }
    .height('100%')
    .padding(15)
    .backgroundColor('#f5f5f5')
  }
}

2)参数初始化组件(具名插槽)

需求:需要传入内容结构和底部结构

java 复制代码
@Component
struct PanelComp {
  title: string
  more: string
  @BuilderParam
  panelContent: () => void
  @BuilderParam
  panelFooter: () => void

  build() {
    Column() {
      Row() {
        Text(this.title)
          .layoutWeight(1)
          .fontWeight(600)
        Row() {
          Text(this.more)
            .fontSize(14)
            .fontColor('#666666')
          Image($r('app.media.ic_public_arrow_right'))
            .width(16)
            .fillColor('#666666')
        }
      }
      .padding(10)

      Row() {
        this.panelContent()
      }
      .height(100)
      Row() {
        this.panelFooter()
      }
      .height(50)
    }
    .borderRadius(12)
    .backgroundColor('#fff')
  }
}

@Entry
@Component
struct Index {
  @Builder
  ContentBuilderA() {
    Text('评价内容')
  }
  @Builder
  FooterBuilderA() {
    Text('评价底部')
  }

  build() {
    Column() {
      GridRow({ columns: 2, gutter: 15 }) {
        GridCol({ span: 2 }) {
          PanelComp({
            title: '评价(2000+)',
            more: '好评率98%',
            panelFooter: this.FooterBuilderA,
            panelContent: this.ContentBuilderA
          })
        }

        // GridCol() {
        //   PanelComp({ title: '推荐', more: '查看全部' }){
        //     Text('推荐内容')
        //   }
        // }
        //
        // GridCol() {
        //   PanelComp({ title: '体验', more: '4 条测评' }){
        //     Text('体验内容')
        //   }
        // }
      }
    }
    .height('100%')
    .padding(15)
    .backgroundColor('#f5f5f5')
  }
}
  • 当子组件使用一个 @BuilderParam 的时候,使用组件的时候在尾随 {} 插入UI结构
  • 当子组件使用多个 @BuilderParam 的时候,使用组件的时候 Comp({ xxx: this.builderFn }) 传入
  • 子组件本身可以提供一个默认的 @Builder 函数作为 @BuilderParam 备用函数,当做备用内容使用

4. 构建函数-系统组件自定义UI

在一些系统组件中,根据配置无法达到预期UI,可以使用 @Builder 构建函数自定义UI,前提该组件支持自定义。

在一些系统组件中,根据配置无法达到预期UI,可以使用 @Builder 构建函数自定义UI,前提该组件支持自定义。

需求:自定义 Tabs 组件的 TabBar UI结构

java 复制代码
class ToolBarItem {
  defaultIcon: string | Resource
  activeIcon: string | Resource
  label: string
}

@Entry
@Component
struct Index {
  @State
  activeIndex: number = 0
  toolBars: ToolBarItem[] = [
    { defaultIcon: $r('app.media.home'), activeIcon: $r('app.media.home_select'), label: '首页' },
    { defaultIcon: $r('app.media.project'), activeIcon: $r('app.media.project_select'), label: '项目' },
    { defaultIcon: $r('app.media.interview'), activeIcon: $r('app.media.interview_select'), label: '面经' },
    { defaultIcon: $r('app.media.mine'), activeIcon: $r('app.media.mine_select'), label: '我的' }
  ]

  @Builder
  TabBarBuilder(item: ToolBarItem, index: number) {
    Column() {
      Image(this.activeIndex === index ? item.activeIcon : item.defaultIcon)
        .width(24)
      Text(item.label)
        .fontSize(12)
        .margin({ top: 4 })
        .lineHeight(12)
        .fontColor(this.activeIndex === index ? '#000' : '#aaa')
    }
  }

  build() {
    Tabs({
      index: this.activeIndex
    }) {
      ForEach(this.toolBars, (item: ToolBarItem, index: number) => {
        TabContent() {
          Text(index.toString())
        }
        .tabBar(this.TabBarBuilder(item, index))
      })
    }
    .barPosition(BarPosition.End)
    .onChange(index => this.activeIndex = index)
  }
}

👀关注公众号:Android老皮!!!欢迎大家来找我探讨交流👀

相关推荐
裴云飞2 小时前
鸿蒙性能优化之布局优化
性能优化·harmonyos
PlumCarefree12 小时前
mp4(H.265编码)转为本地RTSP流
音视频·harmonyos·h.265
鸿蒙自习室15 小时前
鸿蒙网络管理模块04——网络连接管理
华为·harmonyos·鸿蒙·媒体
小Q的编程笔记17 小时前
HarmonyOS:AVPlayer 与 XComponent 联手打造定制化视频播放器
harmonyos
训山1 天前
【10】纯血鸿蒙HarmonyOS NEXT星河版开发0基础学习笔记-泛型基础全解(泛型函数、泛型接口、泛型类)及参数、接口补充
笔记·学习·华为·harmonyos·鸿蒙系统
云兮Coder1 天前
鸿蒙 HarmonyNext 与 Flutter 的异同之处
flutter·华为·harmonyos
Android技术栈1 天前
鸿蒙开发(NEXT/API 12)【应用间消息通信】手机侧应用开发
嵌入式硬件·信息与通信·harmonyos·鸿蒙·鸿蒙系统·openharmony
lqj_本人1 天前
flutter_鸿蒙next(win)环境搭建
flutter·华为·harmonyos
zzlyx991 天前
鸿蒙ArkUI实战开发-主打自研语言及框架
华为·harmonyos
zzlyx992 天前
方舟开发框架(ArkUI)可运行 OpenHarmony、HarmonyOS、Android、iOS等操作系统
华为·harmonyos