鴻蒙應(yīng)用開發(fā)-組件構(gòu)建函數(shù)

自定義構(gòu)建函數(shù)

1. 構(gòu)建函數(shù)-@Builder

ArkUI還提供了一種更輕量的UI元素復(fù)用機(jī)制 @Builder铲球,可以將重復(fù)使用的UI元素抽象成一個(gè)方法,在 build 方法里調(diào)用晰赞。

  • 組件內(nèi)定義
  • 全局定義

1)組件內(nèi)定義

@Builder MyBuilderFunction() {}
this.MyBuilderFunction()

2)全局定義

@Builder function MyGlobalBuilderFunction() {}
MyGlobalBuilderFunction()

?????? 練習(xí)案例→商品詳情-更多按鈕


1.png
@Entry
@Component
struct Index {
  build() {
    Column() {
      GridRow({ columns: 2, gutter: 15 }) {
        GridCol({ span: 2 }) {
          Column() {
            Row() {
              Text('評價(jià)(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('體驗(yàn)')
                .layoutWeight(1)
                .fontWeight(600)
              // TODO
            }
            .padding(10)

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

使用 @Builder 提取UI結(jié)構(gòu)

@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('評價(jià)(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('體驗(yàn)')
                .layoutWeight(1)
                .fontWeight(600)
              this.MoreBuilder()
            }
            .padding(10)

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

小結(jié):

  • 遇到非遍歷情況下稼病,一個(gè)組件分散著相同的UI結(jié)構(gòu),可以使用 @Builder 更輕量
    其他:

  • GridRow GridCol 柵格布局

2. 構(gòu)建函數(shù)-傳參傳遞

1)按值傳遞(場景:構(gòu)建不同的UI)

@Builder MyBuilderFunction( title: string ) {}
this.MyBuilderFunction('Title')

需求:不同板塊查看更多文案不一樣

  • 評價(jià) 好評率 98%

  • 推薦 查看全部

  • 體驗(yàn) 4 條測評


    2.png
@Builder
  MoreBuilder (title: string) {
    Row() {
      Text(title)
        .fontSize(14)
        .fontColor('#666666')
      Image($r('app.media.ic_public_arrow_right'))
        .width(16)
        .fillColor('#666666')
    }
  }
this.MoreBuilder('好評率 98%')
this.MoreBuilder('查看全部')
this.MoreBuilder('4 條測評')

2)引用傳遞(場景:當(dāng)傳遞的數(shù)據(jù)更新掖鱼,需要更新UI)
需求:

  • 點(diǎn)擊按鈕后模擬加載好評率數(shù)據(jù)
3.png
@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('獲取數(shù)據(jù)')
        .margin({ bottom: 15 })
        .onClick(() => {
          this.rate = 99
        })
      GridRow({ columns: 2, gutter: 15 }) {
        GridCol({ span: 2 }) {
          Column() {
            Row() {
              Text('評價(jià)(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('體驗(yàn)')
                .layoutWeight(1)
                .fontWeight(600)
              this.MoreBuilder({ title: '4 條測評' })
            }
            .padding(10)

            Row()
              .height(100)
          }
          .borderRadius(12)
          .backgroundColor('#fff')
        }
      }
    }
    .height('100%')
    .padding(15)
    .backgroundColor('#f5f5f5')
  }
}
  • 使用** @Builder** 復(fù)用邏輯的時(shí)候然走,支持傳參可以更靈活的渲染UI
  • 參數(shù)可以使用狀態(tài)數(shù)據(jù),不過建議通過對象的方式傳入 @Builder
  1. 構(gòu)建函數(shù)-@BuilderParam 傳遞UI
    @BuilderParam 該裝飾器用于聲明任意UI描述的一個(gè)元素戏挡,類似 slot 占位符

前置知識
組件屬性初始化:

  • 定義組件聲明屬性 title: string
  • 使用組件初始化屬性 Comp({ title: string })
  • 尾隨閉包初始化組件

    • 組件內(nèi)有且僅有一個(gè)使用 @BuilderParam 裝飾的屬性
  • 參數(shù)初始化組件

    • 組件內(nèi)有多個(gè)使用 @BuilderParam 裝飾器屬性

1)尾隨閉包初始化組件(默認(rèn)插槽)

需求:

  • 標(biāo)題文字和更多文案通過屬性傳入
  • 內(nèi)容結(jié)構(gòu)需要傳入


    4.png
@Component
struct PanelComp {
  title: string
  more: string
  @BuilderParam
  panelContent: () => void = this.DefaultPanelContent

  // 備用 Builder
  @Builder
  DefaultPanelContent () {
    Text('默認(rèn)內(nèi)容')
  }

  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: '評價(jià)(2000+)', more: '好評率98%' })
        }

        GridCol() {
          PanelComp({ title: '推薦', more: '查看全部' }){
            Text('推薦內(nèi)容')
          }
        }

        GridCol() {
          PanelComp({ title: '體驗(yàn)', more: '4 條測評' }){
            Text('體驗(yàn)內(nèi)容')
          }
        }
      }
    }
    .height('100%')
    .padding(15)
    .backgroundColor('#f5f5f5')
  }
}

2)參數(shù)初始化組件(具名插槽)

需求:需要傳入內(nèi)容結(jié)構(gòu)和底部結(jié)構(gòu)


6.png
@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('評價(jià)內(nèi)容')
  }
  @Builder
  FooterBuilderA() {
    Text('評價(jià)底部')
  }

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

        // GridCol() {
        //   PanelComp({ title: '推薦', more: '查看全部' }){
        //     Text('推薦內(nèi)容')
        //   }
        // }
        //
        // GridCol() {
        //   PanelComp({ title: '體驗(yàn)', more: '4 條測評' }){
        //     Text('體驗(yàn)內(nèi)容')
        //   }
        // }
      }
    }
    .height('100%')
    .padding(15)
    .backgroundColor('#f5f5f5')
  }
}
  • 當(dāng)子組件使用一個(gè) @BuilderParam 的時(shí)候芍瑞,使用組件的時(shí)候在尾隨 {} 插入U(xiǎn)I結(jié)構(gòu)
  • 當(dāng)子組件使用多個(gè) @BuilderParam 的時(shí)候,使用組件的時(shí)候 Comp({ xxx: this.builderFn }) 傳入
  • 子組件本身可以提供一個(gè)默認(rèn)的 @Builder 函數(shù)作為 @BuilderParam 備用函數(shù)褐墅,當(dāng)做備用內(nèi)容使用

4. 構(gòu)建函數(shù)-系統(tǒng)組件自定義UI

在一些系統(tǒng)組件中拆檬,根據(jù)配置無法達(dá)到預(yù)期UI,可以使用 @Builder 構(gòu)建函數(shù)自定義UI妥凳,前提該組件支持自定義竟贯。

在一些系統(tǒng)組件中,根據(jù)配置無法達(dá)到預(yù)期UI逝钥,可以使用 @Builder 構(gòu)建函數(shù)自定義UI屑那,前提該組件支持自定義。

7.jpeg

需求:自定義 Tabs 組件的 TabBar UI結(jié)構(gòu)

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: '項(xiàng)目' },
    { defaultIcon: $r('app.media.interview'), activeIcon: $r('app.media.interview_select'), label: '面經(jīng)' },
    { 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)
  }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市持际,隨后出現(xiàn)的幾起案子沃琅,更是在濱河造成了極大的恐慌,老刑警劉巖选酗,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件阵难,死亡現(xiàn)場離奇詭異岳枷,居然都是意外死亡芒填,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進(jìn)店門空繁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來殿衰,“玉大人,你說我怎么就攤上這事盛泡∶葡椋” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵傲诵,是天一觀的道長凯砍。 經(jīng)常有香客問我,道長拴竹,這世上最難降的妖魔是什么悟衩? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮栓拜,結(jié)果婚禮上座泳,老公的妹妹穿的比我還像新娘。我一直安慰自己幕与,他們只是感情好挑势,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著啦鸣,像睡著了一般潮饱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上诫给,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天饼齿,我揣著相機(jī)與錄音,去河邊找鬼蝙搔。 笑死缕溉,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的吃型。 我是一名探鬼主播证鸥,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了枉层?” 一聲冷哼從身側(cè)響起泉褐,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎鸟蜡,沒想到半個(gè)月后膜赃,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡揉忘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年跳座,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片泣矛。...
    茶點(diǎn)故事閱讀 39,779評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡疲眷,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出您朽,到底是詐尸還是另有隱情狂丝,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布哗总,位于F島的核電站几颜,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏讯屈。R本人自食惡果不足惜蛋哭,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望耻煤。 院中可真熱鬧具壮,春花似錦、人聲如沸哈蝇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽炮赦。三九已至怜跑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間吠勘,已是汗流浹背性芬。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留剧防,地道東北人植锉。 一個(gè)月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像峭拘,于是被迫代替她去往敵國和親俊庇。 傳聞我的和親對象是個(gè)殘疾皇子狮暑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容