鴻蒙應(yīng)用開發(fā)-初見:ArkUI

編程范式:命令式->聲明式

以一個(gè)卡片的實(shí)現(xiàn)做下講解

命令式

簡單講就是需要開發(fā)用代碼一步一步進(jìn)行布局湃缎,這個(gè)過程需要開發(fā)全程參與昌渤。

  • Objective-C
UIView *cardView = [[UIView alloc] init];
cardView.backgroundColor = [UIColor whiteColor];
cardView.layer.cornerRadius = 16;
cardView.clipsToBounds = YES;
[self.view addSubview:cardView];
[cardView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.left.mas_equalTo(16);
    make.right.mas_offset(-16);
    make.height.mas_equalTo(116);
    make.top.mas_equalTo(100);
}];
    
NSString *imgUrl = @"https://ke-image.ljcdn.com//110000-inspection//pc1_nBllrJgGj_1.jpg.280x210.jpg";
UIImageView *imgView = [[UIImageView alloc] init];
imgView.backgroundColor = [UIColor lightGrayColor];
[imgView sd_setImageWithURL:[NSURL URLWithString:imgUrl]];
[cardView addSubview:imgView];
[imgView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.bottom.mas_offset(0);
    make.left.mas_equalTo(0);
    make.width.mas_equalTo(107);
}];

UILabel *titleLbl = [[UILabel alloc] init];
titleLbl.font = [UIFont systemFontOfSize:14 weight:UIFontWeightBold];
titleLbl.textColor = [UIColor blackColor];
titleLbl.text = @"萬柳書院新一區(qū) 南北向滿五唯一";
[cardView addSubview:titleLbl];
[titleLbl mas_makeConstraints:^(MASConstraintMaker *make) {
    make.left.mas_equalTo(imgView.mas_right).mas_offset(12);
    make.right.mas_offset(-12);
    make.top.mas_equalTo(16);
}];

UILabel *subTitleLbl = [[UILabel alloc] init];
subTitleLbl.textColor = [UIColor blackColor];
subTitleLbl.font = [UIFont systemFontOfSize:12 weight:UIFontWeightRegular];
subTitleLbl.text = @"4室2廳/278.35㎡/南 北/萬柳書院";
[cardView addSubview:subTitleLbl];
[subTitleLbl mas_makeConstraints:^(MASConstraintMaker *make) {
    make.left.right.mas_equalTo(titleLbl);
    make.top.mas_equalTo(titleLbl.mas_bottom).mas_offset(8);
}];

UILabel *priceLbl = [[UILabel alloc] init];
priceLbl.font = [UIFont systemFontOfSize:14 weight:UIFontWeightBold];
priceLbl.textColor = [UIColor redColor];
priceLbl.text = @"4238萬";
[cardView addSubview:priceLbl];
[priceLbl mas_makeConstraints:^(MASConstraintMaker *make) {
    make.left.mas_equalTo(titleLbl);
    make.bottom.mas_offset(-16);
}];

UILabel *avgPriceLbl = [[UILabel alloc] init];
avgPriceLbl.textColor = [UIColor lightGrayColor];
avgPriceLbl.font = [UIFont systemFontOfSize:12 weight:UIFontWeightRegular];
avgPriceLbl.text = @"155,445元/平";
[cardView addSubview:avgPriceLbl];
[avgPriceLbl mas_makeConstraints:^(MASConstraintMaker *make) {
    make.left.mas_equalTo(priceLbl.mas_right).mas_offset(2);
    make.right.mas_lessThanOrEqualTo(titleLbl.mas_right);
    make.bottom.mas_equalTo(priceLbl);
}];

聲明式

聲明式則是由開發(fā)使用語言描述UI頁面長什么樣子腌逢,之后全權(quán)交給引擎去做

  1. 對頁面結(jié)構(gòu)進(jìn)行大的拆解扭弧。比如上面卡片分左右兩大部分
  2. 選用合適的容器組件進(jìn)行頁面描述
  3. 針對拆解出來的每個(gè)部分重復(fù)上面的兩步,直到無法拆解只能使用基本組件描述為止

比如上面的卡片可以進(jìn)行如下的拆分

  1. 整體是一個(gè)Row容器著恩,分為左右兩大部分洒嗤,左邊是圖片箫荡,右邊是一個(gè)Column容器
  2. 右邊Column容器又拆分為兩大部分,上面是標(biāo)題和描述渔隶,下面是價(jià)格羔挡。兩部分按照space-between布局
  3. 上面的標(biāo)題和描述作為一個(gè)整體,里面拆分成Column的兩個(gè)組件
  4. 下面價(jià)格可以直接使用系統(tǒng)組件Text

ReactNative

<View
  style={{
    borderRadius: 8,
    marginHorizontal: 16,
    flexDirection: 'row',
    backgroundColor: 'white',
    overflow: 'hidden',
    height: 116,
  }}>
  <Image
    source={{
      uri: 'https://ke-image.ljcdn.com//110000-inspection//pc1_nBllrJgGj_1.jpg.280x210.jpg',
    }}
    style={{width: 107, backgroundColor: '#eee'}}
  />
  <View
    style={{
      marginVertical: 16,
      marginHorizontal: 12,
      flex: 1,
      justifyContent: 'space-between',
    }}>
    <View>
      <Text style={{fontSize: 14, color: '#222', fontWeight: '500'}}>
        萬柳書院新一區(qū) 南北向滿五唯一
      </Text>
      <Text style={{fontSize: 11, color: '#222', marginTop: 8}}>
        4室2廳/278.35㎡/南 北/萬柳書院
      </Text>
    </View>
    <View
      style={{flexDirection: 'row', marginTop: 8, alignItems: 'flex-end'}}>
      <Text
        style={{
          fontSize: 17,
          color: '#E62222',
          fontWeight: 'bold',
        }}>
        4238萬
      </Text>
      <Text style={{fontSize: 11, color: '#999', marginLeft: 6}}>
        155,445元/平
      </Text>
    </View>
  </View>
</View>

SwiftUI

HStack(spacing:0) {
    AsyncImage(url: URL(string: "https://ke-image.ljcdn.com//110000-inspection//pc1_nBllrJgGj_1.jpg.280x210.jpg"))
        .frame(width:107)
        .aspectRatio(contentMode: .fill)
        .clipped()

    VStack(alignment: .leading,
           spacing:0) {
        VStack(alignment: .leading,
               spacing:0) {
            Text("萬柳書院新一區(qū) 南北向滿五唯一")
                .lineLimit(1)
                .font(.system(size: 14))
                .foregroundColor(.black)
                .fontWeight(.bold)
            Text("4室2廳/278.35㎡/南 北/萬柳書院")
                .lineLimit(1)
                .font(.system(size: 12))
                .foregroundColor(.black)
                .padding(.top, 8)
        }

        Spacer()

        HStack(alignment: .bottom,
               spacing:2) {
            Text("4238萬")
                .font(.system(size: 14))
                .foregroundColor(.red)
                .fontWeight(.bold)
            Text("155,445元/平")
                .font(.system(size: 12))
                .foregroundColor(.secondary)
                .padding(.leading, 2)
        }
    }
           .padding(.vertical, 16)
           .padding(.horizontal, 12)

    Spacer()
}
.frame(height: 116)
.background(.white)
.clipShape(RoundedRectangle(cornerRadius: 8))
.padding(.horizontal, 16)
}

ArkUI

  Row() {
    Row() {
      Image("https://ke-image.ljcdn.com//110000-inspection//pc1_nBllrJgGj_1.jpg.280x210.jpg")
        .width(107)
        .height("100%")
        .objectFit(ImageFit.Cover)
      Column() {
        Column() {
          Text("柳書院新一區(qū) 南北向滿五唯一")
            .fontSize(16)
            .fontColor("#222")
            .maxLines(1)
          Text("4室2廳/278.35㎡/南 北/萬柳書院")
            .fontSize(14)
            .fontColor("#222")
            .maxLines(1)
            .margin({ top: 8 })
        }
        .alignItems(HorizontalAlign.Start)

        Row() {
          Text("4238萬")
            .fontSize(15)
            .fontColor("#E62222")
            .fontWeight(FontWeight.Bold)
          Text("155,445元/平")
            .fontSize(13)
            .fontColor("#222")
            .margin({ left: 2 })
        }
        .justifyContent(FlexAlign.Start)
        .alignItems(VerticalAlign.Bottom)
      }
      .width("100%")
      .height("100%")
      .padding({ top: 16, bottom: 16, left: 12, right: 12 })
      .alignItems(HorizontalAlign.Start)
      .justifyContent(FlexAlign.SpaceBetween)
    }
    .borderRadius(8)
    .margin({ left: 16, right: 16 })
    .backgroundColor(Color.White)
    .justifyContent(FlexAlign.Start)
    .clip(true)
  }
  .height(116)
  .width("100%")

小結(jié)

  1. 從上面的例子可以看出來间唉,聲明式語法只需要我們描述UI長什么樣就行绞灼。不需要做太多布局計(jì)算的工作,讓我們少掉一些頭發(fā)

  2. ArkUI和SwiftUI的語法最像终吼,甚至它們的狀態(tài)管理也很像镀赌,都是提供了狀態(tài)綁定和監(jiān)聽機(jī)制來更新UI樣式

聲明式UI布局原理簡述

Flutter中Widget的布局原理參考

Flutter中Widget的布局原理如下圖所示氯哮。想了解更多Flutter的布局原理可以查看 深入理解 Flutter 布局約束

SwiftUI中的View布局原理參考

SwiftUI中的布局原理可以參考下圖际跪。想了解細(xì)節(jié),可參考 SwiftUI 中布局的工作原理

小結(jié)

聲明式布局想要布局子視圖都會經(jīng)歷由上到下的一個(gè)過程喉钢,只有知道了子視圖的大小之后才能根據(jù)對齊方式將子視圖放置在準(zhǔn)確的位置姆打。

聲明式布局幾乎都是下面這個(gè)套路

  1. 父視圖給子視圖一個(gè)布局約束(作為Root的根視圖默認(rèn)是充滿屏幕的,它給子視圖的約束就是屏幕大谐λ洹)
  2. 子視圖渲染并將自身大小返回給父視圖
  3. 父視圖根據(jù)子視圖的大小和設(shè)定的對齊方式計(jì)算要放置的位置
  4. 子視圖的布局也遵循以上三步進(jìn)行遞歸幔戏。整個(gè)過程是深度優(yōu)先的

ArkUI

ArkUI官方鏈接

方舟開發(fā)框架(簡稱ArkUI)是鴻蒙開發(fā)的UI框架,提供如下兩種開發(fā)范式税课,我們 只學(xué)聲明式開發(fā)范式

  1. 基于ArkTS的聲明式開發(fā)范式
  2. 兼容JS的類Web開發(fā)范式

整體架構(gòu)圖

我們使用ArkTS寫完頁面描述后闲延,交給語言運(yùn)行時(shí)進(jìn)行語法解析痊剖,再之后由C++編寫的后端引擎將UI轉(zhuǎn)換為渲染指令交給渲染引擎繪制到屏幕上

ArkUI語法初見

  1. ArkTS對TypeScript語言進(jìn)行擴(kuò)展,提供值類型結(jié)構(gòu)struct垒玲。
  2. struct定義自定義組件陆馁,必須搭配Component或者CustomDialog使用
  3. ArkUI中組件定義和狀態(tài)管理都是通過裝飾器來做的。TS中的裝飾器主要有類裝飾器合愈、屬性裝飾器叮贩、方法裝飾器以及參數(shù)裝飾器四種
  4. 事件方法和屬性方法只是方法的入?yún)⒉灰粯樱粋€(gè)是基本值或者表達(dá)式值佛析,一個(gè)是函數(shù)益老。
  5. 在TS中函數(shù)我們就把函數(shù)當(dāng)成變量來用就行,只不過普通變量是存儲一個(gè)類型的值寸莫,而函數(shù)用來存儲一個(gè)輸入到輸出的轉(zhuǎn)變過程
  6. 還記得我們上面說的描述UI嘛捺萌,在這里就在build函數(shù)中描述”炀ィ框架會自動調(diào)用build互婿,不需要我們手動調(diào)用

從代碼到UI顯示的整體渲染流程

ArkUI的渲染分為兩大情況

從創(chuàng)建到顯示(①~⑤)

① 通過devEco將源碼編譯成帶類型標(biāo)識的字節(jié)碼文件,同時(shí)攜帶創(chuàng)建這個(gè)結(jié)構(gòu)所需信息的指令流

② 通過跨語言調(diào)用生成C++層的Component樹辽狈。這一步只是把ArkTS描述轉(zhuǎn)變成了使用C++描述

③ 通過Component樹生成Element樹慈参,Element是Component的實(shí)例,用于表示一個(gè)具體的組件節(jié)點(diǎn)刮萌。界面在運(yùn)行時(shí)的樹形結(jié)構(gòu)就是通過Element樹來維持的驮配,同時(shí)自動更新的diff算法也是依賴Element樹來減少復(fù)雜度的

④ 對于每個(gè)可顯示的Element都會為其創(chuàng)建對應(yīng)的RenderNode。RenderNode負(fù)責(zé)一個(gè)節(jié)點(diǎn)的顯示信息着茸,它形成的Render樹維護(hù)著整個(gè)界面渲染需要用到的信息壮锻,包括位置、大小涮阔、繪制命令等猜绣。后續(xù)的布局、繪制都是在Render樹上進(jìn)行的

⑤ 實(shí)現(xiàn)真正的渲染并顯示繪制結(jié)果

按鈕點(diǎn)擊到更新顯示(⑥~?)

⑥ 點(diǎn)擊事件傳遞到組件敬特,組件的onClick事件方法被觸發(fā)執(zhí)行

⑦ 由于onClick事件方法中@State注解過的變量改變了掰邢,相應(yīng)getter/setter函數(shù)會被觸發(fā)

⑧ 狀態(tài)管理模塊定位出關(guān)聯(lián)的UI組件

⑨ 狀態(tài)管理模塊更新相應(yīng)的Element樹的信息

⑩ 更新相應(yīng)的UI組件的渲染信息

? 界面顯示,與⑤類似

盒子模型

上面我們說的布局原理伟阔,子視圖上報(bào)給父視圖自身大小的值是指 組件內(nèi)容區(qū)的大小

ArkUI中常用布局容器

如何選擇使用哪種布局

線性布局(Row/Column)

  1. 線性布局的子元素在線性方向上(水平方向和垂直方向)依次排列
  2. 線性布局容器包括 Row] 和 Column 辣之。Column容器內(nèi)子元素按照垂直方向排列,Row容器內(nèi)子元素按照水平方向排列

主軸

  1. 線性布局容器在布局方向上的軸線皱炉,子元素默認(rèn)沿主軸排列怀估。
  2. Row容器主軸為橫向,Column容器主軸為縱向。通過justifyContent屬性設(shè)置子元素在容器主軸上的排列方式
  3. 默認(rèn)相鄰子元素是緊貼著的多搀,也可以通過space設(shè)置子元素間的間距
Column容器內(nèi)子元素在主軸上的排列

主軸方向:垂直向下

Column() {
...
}.justifyContent(FlexAlign.Start)
  1. justifyContent(FlexAlign.Start):元素在主軸方向首端對齊歧蕉,第一個(gè)元素與行首對齊,同時(shí)后續(xù)的元素與前一個(gè)對齊
  2. justifyContent(FlexAlign.Center):元素在主軸方向中心對齊康铭,第一個(gè)元素與行首的距離與最后一個(gè)元素與行尾距離相同
  3. justifyContent(FlexAlign.End):元素在主軸方向尾部對齊廊谓,最后一個(gè)元素與行尾對齊,其他元素與后一個(gè)對齊
  4. justifyContent(FlexAlign.Spacebetween):主軸方向均勻分配元素麻削,相鄰元素之間距離相同蒸痹。第一個(gè)元素與行首對齊,最后一個(gè)元素與行尾對齊
  5. justifyContent(FlexAlign.SpaceAround):主軸方向均勻分配元素呛哟,相鄰元素之間距離相同叠荠。第一個(gè)元素到行首的距離和最后一個(gè)元素到行尾的距離是相鄰元素之間距離的一半
  6. justifyContent(FlexAlign.SpaceEvenly):主軸方向均勻分配元素,相鄰元素之間的距離扫责、第一個(gè)元素與行首的間距榛鼎、最后一個(gè)元素到行尾的間距都完全一樣
Row容器內(nèi)子元素在主軸上的排列

主軸方向:水平向右

Row() {
...
}.justifyContent(FlexAlign.Start)
  1. justifyContent(FlexAlign.Start):元素在主軸方向首端對齊,第一個(gè)元素與行首對齊鳖孤,同時(shí)后續(xù)的元素與前一個(gè)對齊
  2. justifyContent(FlexAlign.Center):元素在主軸方向中心對齊者娱,第一個(gè)元素與行首的距離與最后一個(gè)元素與行尾距離相同
  3. justifyContent(FlexAlign.End):元素在主軸方向尾部對齊,最后一個(gè)元素與行尾對齊苏揣,其他元素與后一個(gè)對齊
  4. justifyContent(FlexAlign.Spacebetween):主軸方向均勻分配元素黄鳍,相鄰元素之間距離相同。第一個(gè)元素與行首對齊平匈,最后一個(gè)元素與行尾對齊
  5. justifyContent(FlexAlign.SpaceAround):主軸方向均勻分配元素框沟,相鄰元素之間距離相同。第一個(gè)元素到行首的距離和最后一個(gè)元素到行尾的距離是相鄰元素之間距離的一半
  6. justifyContent(FlexAlign.SpaceEvenly):主軸方向均勻分配元素增炭,相鄰元素之間的距離忍燥、第一個(gè)元素與行首的間距、最后一個(gè)元素到行尾的間距都完全一樣

交叉軸

  1. 垂直于主軸方向的軸線隙姿。Row容器交叉軸為縱向梅垄,Column容器交叉軸為橫向。
  2. 通過alignItems屬性設(shè)置子元素在交叉軸(排列方向的垂直方向)上的對齊方式
  3. alignSelf屬性用于控制單個(gè)子元素在容器交叉軸上的對齊方式输玷,其優(yōu)先級高于alignItems屬性队丝,如果設(shè)置了alignSelf屬性,則在單個(gè)子元素上會覆蓋alignItems屬性
Column容器內(nèi)子元素在水平方向上的排列
Column() {
...
}.alignItems(HorizontalAlign.Start)
  1. HorizontalAlign.Start:子元素在水平方向左對齊
  2. HorizontalAlign.Center:子元素在水平方向居中對齊
  3. HorizontalAlign.End:子元素在水平方向右對齊饲嗽。
Row容器內(nèi)子元素在垂直方向上的排列
Row() {
...
}.alignItems(VerticalAlign.Top)
  1. VerticalAlign.Top:子元素在垂直方向頂部對齊
  2. VerticalAlign.Center:子元素在垂直方向居中對齊
  3. VerticalAlign.Bottom:子元素在垂直方向底部對齊

層疊布局(Stack)

  1. 層疊布局主要用于實(shí)現(xiàn)基于Z軸的布局炭玫,容器中的子元素(子組件)依次入棧,后一個(gè)子元素覆蓋前一個(gè)子元素貌虾,子元素可以疊加,也可以通過zIndex設(shè)置位置
  2. 可以通過 alignContent參數(shù) 實(shí)現(xiàn)位置的相對移動
Stack({ alignContent: Alignment.BottomStart })

彈性布局(Flex)

  1. Row和Column容器只支持單方向的布局裙犹。你可以把Flex理解為它倆的升級版尽狠,能更靈活的控制布局方向和子元素布局衔憨。
  2. 可以設(shè)置布局方向,是否自動換行等

彈性布局方向圖

Flex({ direction: FlexDirection.Row })

  1. FlexDirection.Row(默認(rèn)值):主軸為水平方向袄膏,子組件從起始端沿著水平方向開始排布
  2. FlexDirection.RowReverse:主軸為水平方向践图,子組件從終點(diǎn)端沿著FlexDirection. Row相反的方向開始排布
  3. FlexDirection.Column:主軸為垂直方向,子組件從起始端沿著垂直方向開始排布
  4. FlexDirection.ColumnReverse:主軸為垂直方向沉馆,子組件從終點(diǎn)端沿著FlexDirection. Column相反的方向開始排布

主軸為水平方向的Flex容器示意圖

主軸對齊方式

通過justifyContent參數(shù)設(shè)置在主軸方向的對齊方式码党,和Row、Column的主軸對齊方式行為一樣

交叉軸對齊方式

可以通過Flex組件的alignItems參數(shù)設(shè)置子組件在交叉軸的對齊方式斥黑,子組件默認(rèn)使用Flex組件的對齊方式揖盘。但也可以通過alignSelf單獨(dú)設(shè)置對齊方式

Flex({ alignItems: ItemAlign.Start })

ItemAlign.Auto:使用Flex容器中默認(rèn)配置。

ItemAlign.Start:交叉軸方向首部對齊

ItemAlign.Center:交叉軸方向居中對齊

ItemAlign.End:交叉軸方向底部對齊

子組件通過 alignSelf 設(shè)置在父容器交叉軸的對齊格式锌奴,覆蓋Flex布局容器中alignItems配置

相對布局(RelativeContainer)

  1. 相對布局可以讓子元素指定兄弟元素或父容器作為錨點(diǎn)兽狭,基于錨點(diǎn)做位置布局
  2. 必須為RelativeContainer及其子元素設(shè)置ID,用于指定錨點(diǎn)信息鹿蜀。未設(shè)置ID的子元素不會顯示
  3. RelativeContainer ID為“container”箕慧,其余子元素的ID通過id屬性設(shè)置。
  4. 子元素通過 alignRules 指定相對布局規(guī)則

錨點(diǎn)的對齊位置示意圖

一個(gè)示例

@Entry
@Component
struct Index {
  build() {
    Row() {
      RelativeContainer() {
        Row()
          .width(100)
          .height(100)
          .backgroundColor('#FF3333')
          .alignRules({
            top: { anchor: '__container__', align: VerticalAlign.Top },  //以父容器為錨點(diǎn)茴恰,豎直方向頂頭對齊
            middle: { anchor: '__container__', align: HorizontalAlign.Center }  //以父容器為錨點(diǎn)颠焦,水平方向居中對齊
          })
          .id('row1')  //設(shè)置錨點(diǎn)為row1

        Row() {
          Image($r('app.media.icon'))
        }
        .height(100).width(100)
        .alignRules({
          top: { anchor: 'row1', align: VerticalAlign.Bottom },  //以row1組件為錨點(diǎn),豎直方向低端對齊
          left: { anchor: 'row1', align: HorizontalAlign.Start }  //以row1組件為錨點(diǎn)往枣,水平方向開頭對齊
        })
        .id('row2')  //設(shè)置錨點(diǎn)為row2

        Row()
          .width(100)
          .height(100)
          .backgroundColor('#FFCC00')
          .alignRules({
            top: { anchor: 'row2', align: VerticalAlign.Top }
          })
          .id('row3')  //設(shè)置錨點(diǎn)為row3

        Row()
          .width(100)
          .height(100)
          .backgroundColor('#FF9966')
          .alignRules({
            top: { anchor: 'row2', align: VerticalAlign.Top },
            left: { anchor: 'row2', align: HorizontalAlign.End },
          })
          .id('row4')  //設(shè)置錨點(diǎn)為row4

        Row()
          .width(100)
          .height(100)
          .backgroundColor('#FF66FF')
          .alignRules({
            top: { anchor: 'row2', align: VerticalAlign.Bottom },
            middle: { anchor: 'row2', align: HorizontalAlign.Center }
          })
          .id('row5')  //設(shè)置錨點(diǎn)為row5
      }
      .width(300).height(300)
      .border({ width: 2, color: '#6699FF' })
    }
    .height('100%').margin({ left: 30 })
  }
}

創(chuàng)建列表(List)

  1. 列表容器是為了高效處理長列表的容器蒸健,能支持橫向、豎向滾動婉商,數(shù)據(jù)分組似忧,分組頭懸浮等功能
  2. 列表容器內(nèi)的所有子元素必須是 ListItemGroup 或ListItem,我們實(shí)際的內(nèi)容是在這倆容器內(nèi)部的
  3. 創(chuàng)建列表子元素一般使用 ForEach 來減少開發(fā)量

List丈秩、ListItemGroup和ListItem組件關(guān)系

List() {
    ListItem() {
    }
    ListItem() {
    }
    ListItemGroup() {
    }
    LazyForEach(this.dataSource, item => {
        ListItem() {
            ...
        }
    })
}
// 設(shè)置垂直方向
.listDirection(Axis.Vertical)
// 粘性header
.sticky(StickyStyle.Header)
// 兩列
.lanes(2)

創(chuàng)建網(wǎng)格(Grid/GridItem)

  1. 網(wǎng)格布局主要用于處理固定行列的UI盯捌,也支持動態(tài)調(diào)整。很類似iOS中的UICollectionView蘑秽。
  2. Grid 容器的子組件一定是 GridItem

Grid饺著,GridItem關(guān)系

容器內(nèi)每一個(gè)條目對應(yīng)一個(gè)GridItem組件

行列數(shù)量可配

  1. Grid組件提供了rowsTemplate和columnsTemplate屬性用于設(shè)置網(wǎng)格布局行列數(shù)量與尺寸占比。
  2. rowsTemplate和columnsTemplate屬性值是一個(gè)由多個(gè)空格和'數(shù)字+fr'間隔拼接的字符串肠牲,fr的個(gè)數(shù)即網(wǎng)格布局的行或列數(shù)幼衰,fr前面的數(shù)值大小,用于計(jì)算該行或列在網(wǎng)格布局寬度上的占比缀雳,最終決定該行或列的寬度
Grid() {
...
}
.rowsTemplate('1fr 1fr 1fr')
.columnsTemplate('1fr 2fr 1fr')

單個(gè)網(wǎng)格可以橫跨多行或多列

通過設(shè)置GridItem的rowStart渡嚣、rowEnd、columnStart和columnEnd可以實(shí)現(xiàn)單個(gè)網(wǎng)格橫跨多行或多列的場景

Grid() {
    GridItem() {}
    GridItem() {}
    GridItem() {}
    .columnStart(1)
    .columnEnd(2)

    GridItem() {}
    .rowStart(1)
    .rowEnd(2)
    GridItem() {}
    GridItem() {}
    GridItem() {}
    
    GridItem() {}
    .columnStart(1)
    .columnEnd(3)
}
.rowsTemplate('1fr 1fr 1fr')
.columnsTemplate('1fr 1fr 1fr 1fr')
.columnsGap(8)
.rowsGap(8)

其他常用布局容器和組件

  • 創(chuàng)建輪播(Swiper)實(shí)現(xiàn)輪播圖功能
  • 柵格布局(GridRow/GridCol)和Grid布局類似,但是可以根據(jù)設(shè)置的分割點(diǎn)動態(tài)顯示列數(shù)识椰。特別適合做多設(shè)備適配布局
  • Badge 實(shí)現(xiàn)消息小紅點(diǎn)和消息數(shù)功能
  • WaterFlow 實(shí)現(xiàn)瀑布流功能
  • Video 實(shí)現(xiàn)視頻播放功能
  • TextTimer 實(shí)現(xiàn)倒計(jì)時(shí)顯示功能
  • DataPanel 數(shù)據(jù)面板組件绝葡,使用占比圖展示多個(gè)數(shù)據(jù)的占比情況
  • Gauge 以環(huán)形圖表形式展示數(shù)據(jù)
  • Marquee 走馬燈效果

  • PatternLock 圖形密碼鎖組件

  • Rating 評分組件
  • Stepper 步驟導(dǎo)航器組件,主要用于引導(dǎo)介紹功能
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末腹鹉,一起剝皮案震驚了整個(gè)濱河市藏畅,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌功咒,老刑警劉巖愉阎,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異力奋,居然都是意外死亡榜旦,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進(jìn)店門刊侯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來章办,“玉大人,你說我怎么就攤上這事滨彻∨航欤” “怎么了?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵亭饵,是天一觀的道長休偶。 經(jīng)常有香客問我,道長辜羊,這世上最難降的妖魔是什么踏兜? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮八秃,結(jié)果婚禮上碱妆,老公的妹妹穿的比我還像新娘。我一直安慰自己昔驱,他們只是感情好疹尾,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著骤肛,像睡著了一般纳本。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上腋颠,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天繁成,我揣著相機(jī)與錄音,去河邊找鬼淑玫。 笑死巾腕,一個(gè)胖子當(dāng)著我的面吹牛面睛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播祠墅,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼侮穿,長吁一口氣:“原來是場噩夢啊……” “哼歌径!你這毒婦竟也來了毁嗦?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤回铛,失蹤者是張志新(化名)和其女友劉穎狗准,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體茵肃,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡腔长,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了验残。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片捞附。...
    茶點(diǎn)故事閱讀 39,932評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖您没,靈堂內(nèi)的尸體忽然破棺而出鸟召,到底是詐尸還是另有隱情,我是刑警寧澤氨鹏,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布欧募,位于F島的核電站,受9級特大地震影響仆抵,放射性物質(zhì)發(fā)生泄漏跟继。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一镣丑、第九天 我趴在偏房一處隱蔽的房頂上張望舔糖。 院中可真熱鬧,春花似錦莺匠、人聲如沸金吗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽辽聊。三九已至,卻和暖如春期贫,著一層夾襖步出監(jiān)牢的瞬間跟匆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工通砍, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留玛臂,地道東北人烤蜕。 一個(gè)月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像迹冤,于是被迫代替她去往敵國和親讽营。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評論 2 354

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