【Harmony】基礎(chǔ)組件應(yīng)用

這個(gè)結(jié)構(gòu)和Flutter阿、Compose阿挺像,順?biāo)兄?,都為生命式UI方式,看下組件吧:


image.png
image.png

1. 組件介紹:

@Entry

代表一個(gè)界面的入口,跟Activity聲明有點(diǎn)像

@Component

代表是一個(gè)UI布局的結(jié)構(gòu)體聲明,下面跟結(jié)構(gòu)體
結(jié)構(gòu)體內(nèi),組件在build方法內(nèi),每個(gè)組件都必須實(shí)現(xiàn)build方法,是用于定義組件的聲明式UI描述

2. 基礎(chǔ)組件

image.png

基礎(chǔ)組件的聲明式使用,參數(shù)方式傳遞,參數(shù)既可以用直接輸入、也可以來源于資源(當(dāng)然正常編碼都用資源啦,涉及到多語言等自動(dòng)適配啦)

Text

Column() {
  Text(this.message)//外部文字定義使用
    .fontSize('36.00fp')
    .fontWeight(FontWeight.Bold)
  Text("一段文字")//直接字符串
    .fontColor("#ff00ff")
  Text($r("app.string.EntryAbility_label"))//string資源使用
    .fontColor($r('app.color.main_text_color'))//color資源使用
}

Button

Column() {
  Button("button", { type: ButtonType.Normal })//矩形
  Button("button", { type: ButtonType.Capsule })//默認(rèn)的膠囊型
}

容器:

image.png

Colume:列容器

接口 參數(shù)說明
alignItems 水平對(duì)齊:HorizontalAlign枚舉,默認(rèn)Center
justifyContent 垂直對(duì)齊:FlexAlign枚舉,默認(rèn)Top
Column() {
  Text('Text1')
    .width(fp2px(50))
    .height(fp2px(50))
    .backgroundColor(Color.White)
    .textAlign(TextAlign.Center)

  Text('Text2')
    .width(fp2px(50))
    .height(fp2px(50))
    .backgroundColor(Color.White)
    .textAlign(TextAlign.Center)

  Text('Text3')
    .width(fp2px(50))
    .height(fp2px(50))
    .backgroundColor(Color.White)
    .textAlign(TextAlign.Center)
}
.width('100%')
.height('100%')
.backgroundColor(Color.Green)
.alignItems(HorizontalAlign.End)
.justifyContent(FlexAlign.End) 

Row:行容器

接口 參數(shù)說明
alignItems 垂直對(duì)齊:VerticalAlign枚舉,默認(rèn)Center
justifyContent 水平對(duì)齊:FlexAlign枚舉,默認(rèn)Start
Row() {
  Text('Text1')
    .width(fp2px(50))
    .height(fp2px(50))
    .backgroundColor(Color.White)
    .textAlign(TextAlign.Center)

  Text('Text2')
    .width(fp2px(50))
    .height(fp2px(50))
    .backgroundColor(Color.White)
    .textAlign(TextAlign.Center)

  Text('Text3')
    .width(fp2px(50))
    .height(fp2px(50))
    .backgroundColor(Color.White)
    .textAlign(TextAlign.Center)
}
.width('100%')
.height('100%')
.backgroundColor(Color.Green)
.alignItems(VerticalAlign.Center)
.justifyContent(FlexAlign.Start)

Stack:棧容器

堆疊型容器

接口 參數(shù)說明
alignContent 對(duì)齊:Alignment,默認(rèn)是Center
Stack(/*{ alignContent: Alignment.TopStart }*/) {
  Text('Text1')
    .width(fp2px(50))
    .height(fp2px(50))
    .backgroundColor(Color.Orange)
    .textAlign(TextAlign.Center)

  Text('Text2')
    .width(fp2px(30))
    .height(fp2px(30))
    .backgroundColor(Color.Red)
    .textAlign(TextAlign.Center)

  Text('Text3')
    .width(fp2px(20))
    .height(fp2px(20))
    .backgroundColor(Color.Yellow)
    .textAlign(TextAlign.Center)
}
.width('100%')
.height('100%')
.backgroundColor(Color.Green)

如下圖:后面的覆蓋在前面的上面


image.png

練習(xí):靜態(tài)水果排行榜頁(yè)面

build() {
  Column() {
    /*頂部標(biāo)題欄*/
    Row() {
      /*左側(cè)*/
      Row() {
        Image($r('app.media.ic_public_back'))
          .width(22)
          .height(22)
          .margin({ right: 18 })

        Text("排行榜")
          .fontSize(20)
      }
      .width('50%')
      .height(100)
      .justifyContent(FlexAlign.Start)
      /*右側(cè)*/

      Row() {
        Image($r('app.media.loading'))
          .width(22)
          .height(22)
      }
      .width('50%')
      .height(100)
      .justifyContent(FlexAlign.End) //右對(duì)齊
    }
    .width('100%')
    .height(47)
    .padding({ left: 26, right: 26 })
    .margin({ top: 18 })


    /*水果排行榜標(biāo)題*/
    Row() {
      Text("排名")
        .fontSize(14)
        .width('30%')
        .fontColor('#989a9c')
      Text("種類")
        .fontSize(14)
        .width('50%')
        .fontColor('#989a9c')
      Text("得票數(shù)")
        .fontSize(14)
        .width('20%')
        .fontColor('#989a9c')
    }
    .width('90%')
    .padding(15)

    /*水果排行內(nèi)容*/
    Column() {
      List({space: 10}) {
        ListItem() {
          Row() {
            Text("1")
              .width('30%')
            Text("蘋果")
              .width('50%')
            Text("12080")
              .width('20%')
          }
        }

        ListItem() {
          Row() {
            Text("2")
              .width('30%')
            Text("葡萄")
              .width('50%')
            Text("10320")
              .width('20%')
          }
        }

        ListItem() {
          Row() {
            Text("3")
              .width('30%')
            Text("西瓜")
              .width('50%')
            Text("9801")
              .width('20%')
          }
        }
      }
      .width('90%')
      .padding(15)
    }
  }
  .backgroundColor("#F1F3F5")
  .width('100%')
  .height('100%')
}

還是有點(diǎn)像模像樣的啦: 布局拆解后,按橫向縱向排列布局處理,響應(yīng)式寫法確實(shí)帥。就是括號(hào)嵌套層級(jí)有點(diǎn)多,看起來有點(diǎn)難受,看下效果


image.png

練習(xí):動(dòng)態(tài)渲染數(shù)據(jù)

靜態(tài)的每個(gè)自己添加在實(shí)際使用的時(shí)候是不切實(shí)際的,肯定是根據(jù)數(shù)據(jù)進(jìn)行遍歷添加。試一下foreach

/**
 * 水果排行數(shù)組
 */
fruits: Array<Object> = [{
  id: '1',
  name: "蘋果",
  vote: "12080"
}, {
  id: '2',
  name: "葡萄",
  vote: "10320"
}, {
  id: '3',
  name: "西瓜",
  vote: "9801"
}, {
  id: '4',
  name: "香蕉",
  vote: "7546"
}, {
  id: '5',
  name: "菠蘿",
  vote: "1208"
}]
/**
 * 水果排行榜頁(yè)面 靜態(tài)練習(xí)
 */
build() {
  Column() {
    /*頂部標(biāo)題欄*/
    Row() {
      /*左側(cè)*/
      Row() {
        Image($r('app.media.ic_public_back'))
          .width(22)
          .height(22)
          .margin({ right: 18 })

        Text("排行榜")
          .fontSize(20)
      }
      .width('50%')
      .height(100)
      .justifyContent(FlexAlign.Start)
      /*右側(cè)*/

      Row() {
        Image($r('app.media.loading'))
          .width(22)
          .height(22)
      }
      .width('50%')
      .height(100)
      .justifyContent(FlexAlign.End) //右對(duì)齊
    }
    .width('100%')
    .height(47)
    .padding({ left: 26, right: 26 })
    .margin({ top: 18 })


    /*水果排行榜標(biāo)題*/
    Row() {
      Text("排名")
        .fontSize(14)
        .width('30%')
        .fontColor('#989a9c')
      Text("種類")
        .fontSize(14)
        .width('50%')
        .fontColor('#989a9c')
      Text("得票數(shù)")
        .fontSize(14)
        .width('20%')
        .fontColor('#989a9c')
    }
    .width('90%')
    .padding(15)

    /*水果排行內(nèi)容*/
    Column() {
      List({ space: 10 }) {
        /*采用對(duì)象來*/
        ForEach(this.fruits, (item) => {
          ListItem() {
            Row() {
              if (item.id <= 3) {
                Column() {
                  Row() {
                    Text(item.id)
                      .fontSize(14)
                      .fontColor(Color.White)
                  }
                  .width(24)
                  .height(24)
                  .borderRadius(18)
                  .backgroundColor(Color.Blue)
                  .justifyContent(FlexAlign.Center) //水平對(duì)齊
                }
                .width('30%')
                .alignItems(HorizontalAlign.Start) //水平對(duì)齊
              }
              else {
                Column() {
                  Text(item.id)
                    .fontSize(14)
                    .textAlign(TextAlign.Center)//文字居中,對(duì)應(yīng)上面的Row的水平居中
                    .width(24)
                    .height(24)
                }
                .width('30%')
                .alignItems(HorizontalAlign.Start) //水平對(duì)齊
              }
              Text(item.name)
                .width('50%')
              Text(item.vote)
                .width('20%')
            }
          }
        })
      }
      .width('90%')
      .padding(15)
    }
  }
  .backgroundColor("#F1F3F5")
  .width('100%')
  .height('100%')
}

主要關(guān)鍵修改是增加了一個(gè)數(shù)組Array,然后使用foreach來遍歷產(chǎn)生ListItem
效果:


image.png

組件事件修飾器

  • onclick事件
Button("點(diǎn)擊")
  .onClick(event => {
    this.count++
    console.log("點(diǎn)擊事件觸發(fā):" + this.count)
  })
  • @State修飾器
    我們希望對(duì)應(yīng)值修改后能體現(xiàn)在UI上則可以用改狀態(tài)修飾器修飾對(duì)應(yīng)的值定義
@State count: number = 0

#在count變化后, Text控件自動(dòng)會(huì)刷新
Text("文字" + this.count)
  • @Link 修飾器
    通過@link修飾器可以將子組件的變量與父組件的變量建立關(guān)聯(lián)關(guān)系

  • @Builder 修飾器
    可以將組件抽象提取為函數(shù),重復(fù)UI利用,在build里調(diào)用

3. 模塊化

數(shù)據(jù)與頁(yè)面分離:

將頁(yè)面和數(shù)據(jù)分離開到不同文件,可以方便管理代碼
(1)另建ets文件
(2)將類類型、靜態(tài)數(shù)據(jù)聲明放到獨(dú)立的ets中
(3)將類型、數(shù)據(jù)聲明加export,讓外部可以使用
(4)在需要使用的地方,使用import ··· from 方式來引用
如下:

image.png

布局分離:
一個(gè)etx中有多個(gè)view時(shí),可以拆分成不同的自定義view,或者說組合多個(gè)自定義view到布局:

  1. 新建etx文件,使用 子組件方式,修飾結(jié)構(gòu)體
@Component
export struct TitleComponent{
    //這樣實(shí)現(xiàn)build方法即可
  build(){
  }
}
  1. 對(duì)于子組件中有變量要與父控件保持一致時(shí),使用前面說的@Link,建議關(guān)聯(lián)父控件值時(shí),名稱也要與父控件聲明一樣(不一樣也沒啥,傳參綁定)
@Component
struct TitleComponent{
    //關(guān)聯(lián)父控件中傳入變量的值
  @Link isSwitchFruits:boolean
  build(){
    Row() {
      //左側(cè)
      Row() {
        Image($r('app.media.ic_public_back'))
          .width(22)
          .height(22)
          .margin({ right: 18 })

        Text("排行榜")
          .fontSize(20)
      }
      .width('50%')
      .height(100)
      .justifyContent(FlexAlign.Start)

      //右側(cè)

      Row() {
        Image($r('app.media.loading'))
          .width(22)
          .height(22)
          .onClick(() => {
            this.isSwitchFruits = !this.isSwitchFruits
          })
      }
      .width('50%')
      .height(100)
      .justifyContent(FlexAlign.End) //右對(duì)齊
    }
    .width('100%')
    .height(47)
    .padding({ left: 26, right: 26 })
    .margin({ top: 18 })
  }
}

使用時(shí):

//引用
import {TitleComponent} from '../view/TitleComponent'

//使用傳參方式綁定子控件內(nèi)容,左側(cè)為子控件變量,右側(cè)用取值方式取當(dāng)前要傳的值
TitleComponent({sisSwitchFruits:$isSwitchFruits})
  1. 對(duì)于可以重復(fù)利用的使用@Builder
/**
 * 水果排行榜頁(yè)面 靜態(tài)練習(xí)
 */
build() {
  Column() {
    /*頂部標(biāo)題欄*/
    //使用傳參方式綁定子空間內(nèi)容
    TitleComponent({ sisSwitchFruits: $isSwitchFruits })

    //水果排行榜標(biāo)題
    ListTitleComponent()

    /*水果排行內(nèi)容*/
    this.RankList()
  }
  .backgroundColor("#F1F3F5")
  .width('100%')
  .height('100%')
}

/**
 * UI做builder聲明方式,UI組件作為函數(shù)使用,被build內(nèi)調(diào)用
 */
@Builder RankList() {
  Column() {
    List({ space: 10 }) {
      //采用對(duì)象來
      ForEach(this.isSwitchFruits ? this.fruits : this.fruitsData2, (item: Fruit) => {
        ListItem() {
          ItemComponent({
            itemId: item.id,
            itemName: item.name,
            itemVote: item.vote
          })
        }
      })
    }
    .width('90%')
    .padding(15)
  }
}

至此,簡(jiǎn)單的布局就可以啦:
1.簡(jiǎn)單的組件使用布局:Column、Row、Stack、ListItem
2.狀態(tài)改變等:@State 來關(guān)注變化、@link 來子控件關(guān)聯(lián)父控件變量、
3.將view獨(dú)立:獨(dú)立函數(shù)@Builder抽離view到函數(shù),獨(dú)立文件 @Component 和 import、from

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容