鴻蒙一多適配的布局能力

不同的屏幕尺寸,如何適配?鴻蒙提供了自適應(yīng)布局和響應(yīng)式布局。

名稱 簡介
自適應(yīng)布局 拉伸屏幕,頁面的位置關(guān)系沒有發(fā)生變化。自適應(yīng)布局常常需要借助Row組件、Column組件或Flex組件實現(xiàn)。當前自適應(yīng)布局能力有7種:拉伸能力、均分能力、占比能力、縮放能力、延伸能力、隱藏能力、折行能力。
響應(yīng)式布局 拉伸屏幕,頁面的位置關(guān)系發(fā)生變化。響應(yīng)式布局常常與GridRow組件、List組件、Swiper組件或Tabs組件搭配使用。響應(yīng)式布局能力有3種:斷點、媒體查詢、柵格布局。

自適應(yīng)布局

下面介紹自適應(yīng)布局的7種能力。自適應(yīng)布局的7種能力需要牢記于心。

拉伸能力

父組件尺寸發(fā)生變化,增加或減小指定組件的尺寸。

屬性 默認值 描述
flexGrow 0 父容器寬度大于所有子組件寬度的總和,子組件按照比例分配父容器的多余空間。
flexShrink 1 父容器寬度小于所有子組件寬度的總和。子組件按照比例收縮分配父容器的不足空間。
flexBasis 'auto' 設(shè)置組件在Flex容器中主軸方向上基準尺寸。'auto'意味著使用組件原始的尺寸,不做修改。flexBasis屬性不是必須的,通過width或height也可以達到同樣的效果。當flexBasis屬性與width或height發(fā)生沖突時,以flexBasis屬性為準。

下面的示例中,頁面由中間的圖片以及兩側(cè)的留白區(qū)組成,各區(qū)域的屬性配置如下:

  • 中間內(nèi)容區(qū)的寬度設(shè)置為400vp,同時將flexGrow屬性設(shè)置為1,flexShrink屬性設(shè)置為0。
  • 兩側(cè)留白區(qū)的寬度設(shè)置為150vp,同時將flexGrow屬性設(shè)置為0,flexShrink屬性設(shè)置為1。
    父容器的基準尺寸是700vp(150vp+400vp+150vp)??梢酝ㄟ^拖動底部的滑動條改變父容器的尺寸,查看布局變化。
  • 當父容器的尺寸大于700vp時,父容器中多余的空間全部分配給中間內(nèi)容區(qū)。
  • 當父容器的尺寸小于700vp時,左右兩側(cè)的留白區(qū)按照“1:1”的比例收縮。


    示例圖
@Entry
@Component
struct FlexibleCapabilitySample1 {
  @State containerWidth: number = 402

  // 底部滑塊,可以通過拖拽滑塊改變?nèi)萜鞒叽纭?  @Builder slider() {
    Slider({ value: this.containerWidth, min: 402, max: 1000, style: SliderStyle.OutSet })
      .blockColor(Color.White)
      .width('60%')
      .onChange((value: number) => {
        this.containerWidth = value;
      })
      .position({ x: '20%', y: '80%' })
  }

  build() {
    Column() {
      Column() {
        Row() {
          // 通過flexGrow和flexShrink屬性,將多余的空間全部分配給圖片,將不足的控件全部分配給兩側(cè)空白區(qū)域。
          Row().width(150).height(400).backgroundColor('#FFFFFF')
            .flexGrow(0).flexShrink(1)
          Image($r("app.media.illustrator")).width(400).height(400)
            .objectFit(ImageFit.Contain)
            .backgroundColor("#66F1CCB8")
            .flexGrow(1).flexShrink(0)
          Row().width(150).height(400).backgroundColor('#FFFFFF')
            .flexGrow(0).flexShrink(1)
        }
        .width(this.containerWidth)
        .justifyContent(FlexAlign.Center)
        .alignItems(VerticalAlign.Center)
      }

      this.slider()
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F1F3F5')
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center)
  }
}

如果期望將父容器的剩余空間全部分配給某空白區(qū)域時,也可以通過Blank組件實現(xiàn)。注意僅當父組件為Row、Column、Flex組件時,Blank組件才會生效。


示例圖
@Entry
@Component
struct FlexibleCapabilitySample2 {
  @State rate: number = 0.8

  // 底部滑塊,可以通過拖拽滑塊改變?nèi)萜鞒叽?  @Builder slider() {
    Slider({ value: this.rate * 100, min: 30, max: 80, style: SliderStyle.OutSet })
      .blockColor(Color.White)
      .width('60%')
      .onChange((value: number) => {
        this.rate = value / 100;
      })
      .position({ x: '20%', y: '80%' })
  }

  build() {
    Column() {
      Column() {
        Row() {
          Text('飛行模式')
            .fontSize(16)
            .width(135)
            .height(22)
            .fontWeight(FontWeight.Medium)
            .lineHeight(22)
          Blank()      // 通過Blank組件實現(xiàn)拉伸能力
          Toggle({ type: ToggleType.Switch })
            .width(36)
            .height(20)
        }
        .height(55)
        .borderRadius(12)
        .padding({ left: 13, right: 13 })
        .backgroundColor('#FFFFFF')
        .width(this.rate * 100 + '%')
      }

      this.slider()
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F1F3F5')
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center)
  }
}

均分能力

父容器縮放,子組件的尺寸不變,只是中間的間距或者留白按照比例縮放。均分能力可以通過將Row組件、Column組件或Flex組件的justifyContent屬性設(shè)置為FlexAlign.SpaceEvenly實現(xiàn)。

占比能力

子組件的寬高按照預(yù)設(shè)的比例,隨父容器組件發(fā)生變化。占比能力通常有兩種實現(xiàn)方式:

  • 將子組件的寬高設(shè)置為父組件寬高的百分比。
  • 設(shè)置權(quán)重layoutWeight屬性。


    示例圖
@Entry
@Component
struct ProportionCapabilitySample {
  @State rate: number = 0.5

  // 底部滑塊,可以通過拖拽滑塊改變?nèi)萜鞒叽?  @Builder slider() {
    Slider({ value: 100, min: 25, max: 50, style: SliderStyle.OutSet })
      .blockColor(Color.White)
      .width('60%')
      .height(50)
      .onChange((value: number) => {
        this.rate = value / 100
      })
      .position({ x: '20%', y: '80%' })
  }

  build() {
    Column() {
      Column() {
        Row() {
          Column() {
            Image($r("app.media.down"))
              .width(48)
              .height(48)
          }
          .height(96)
          .layoutWeight(1)  // 設(shè)置子組件在父容器主軸方向的布局權(quán)重
          .justifyContent(FlexAlign.Center)
          .alignItems(HorizontalAlign.Center)

          Column() {
            Image($r("app.media.pause"))
              .width(48)
              .height(48)
          }
          .height(96)
          .layoutWeight(1)  // 設(shè)置子組件在父容器主軸方向的布局權(quán)重
          .backgroundColor('#66F1CCB8')
          .justifyContent(FlexAlign.Center)
          .alignItems(HorizontalAlign.Center)

          Column() {
            Image($r("app.media.next"))
              .width(48)
              .height(48)
          }
          .height(96)
          .layoutWeight(1)  // 設(shè)置子組件在父容器主軸方向的布局權(quán)重
          .justifyContent(FlexAlign.Center)
          .alignItems(HorizontalAlign.Center)
        }
        .width(this.rate * 100 + '%')
        .height(96)
        .borderRadius(16)
        .backgroundColor('#FFFFFF')
      }

      this.slider()
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F1F3F5')
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center)
  }
}

縮放能力

設(shè)置aspectRatio寬高比屬性,父容器發(fā)生改變,子組件的寬高比不變。


示例圖
@Entry
@Component
struct ScaleCapabilitySample {
  @State sliderWidth: number = 400
  @State sliderHeight: number = 400

  // 底部滑塊,可以通過拖拽滑塊改變?nèi)萜鞒叽?  @Builder slider() {
   
    Slider({ value: this.sliderHeight, min: 100, max: 400, style: SliderStyle.OutSet })
      .blockColor(Color.White)
      .width('60%')
      .height(50)
      .onChange((value: number) => {
        this.sliderHeight = value
      })
      .position({ x: '20%', y: '80%' })

    Slider({ value: this.sliderWidth, min: 100, max: 400, style: SliderStyle.OutSet })
      .blockColor(Color.White)
      .width('60%')
      .height(50)
      .onChange((value: number) => {
        this.sliderWidth = value;
      })
      .position({ x: '20%', y: '87%' })
  }

  build() {
    Column() {
      Column() {
        Column() {
          Image($r("app.media.illustrator")).width('100%').height('100%')
        }
        .aspectRatio(1)                           // 固定寬高比
        .border({ width: 2, color: "#66F1CCB8"})  // 邊框,僅用于展示效果
      }
      .backgroundColor("#FFFFFF")
      .height(this.sliderHeight)
      .width(this.sliderWidth)
      .justifyContent(FlexAlign.Center)
      .alignItems(HorizontalAlign.Center)

      this.slider()
    }
    .width('100%')
    .height('100%')
    .backgroundColor("#F1F3F5")
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center)
  }
}

延伸能力

子組件隨著父容器尺寸變化顯示或者隱藏。延伸能力通常有兩種實現(xiàn)方式:

  • 通過List組件。
  • 通過Scroll組件配合Row組件或Column組件實現(xiàn)。


    示例圖
@Entry
@Component
struct ExtensionCapabilitySample1 {
  @State rate: number = 0.60
  readonly appList: number [] = [0, 1, 2, 3, 4, 5, 6, 7]

  // 底部滑塊,可以通過拖拽滑塊改變?nèi)萜鞒叽?  @Builder slider() {
    Slider({ value: this.rate * 100, min: 8, max: 60, style: SliderStyle.OutSet })
      .blockColor(Color.White)
      .width('60%')
      .height(50)
      .onChange((value: number) => {
        this.rate = value / 100
      })
      .position({ x: '20%', y: '80%' })
  }

  build() {
    Column() {
      Row({ space: 10 }) {
        // 通過List組件實現(xiàn)隱藏能力
        List({ space: 10 }) {
          ForEach(this.appList, (item:number) => {
            ListItem() {
              Column() {
                Image($r("app.media.startIcon")).width(48).height(48).margin({ top: 8 })
                Text('App name')
                  .width(64)
                  .height(30)
                  .lineHeight(15)
                  .fontSize(12)
                  .textAlign(TextAlign.Center)
                  .margin({ top: 8 })
                  .padding({ bottom: 15 })
              }.width(80).height(102)
            }.width(80).height(102)
          })
        }
        .padding({ top: 16, left: 10 })
        .listDirection(Axis.Horizontal)
        .width('100%')
        .height(118)
        .borderRadius(16)
        .backgroundColor(Color.White)
      }
      .width(this.rate * 100 + '%')

      this.slider()
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F1F3F5')
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center)
  }
}

隱藏能力

給子組件設(shè)置布局優(yōu)先級(displayPriority屬性),父組件尺寸變化,按照優(yōu)先級對子組件進行顯示或者隱藏。


示例圖
@Entry
@Component
struct HiddenCapabilitySample {
  @State rate: number = 0.45

  // 底部滑塊,可以通過拖拽滑塊改變?nèi)萜鞒叽?  @Builder slider() {
    Slider({ value: this.rate * 100, min: 10, max: 45, style: SliderStyle.OutSet })
      .blockColor(Color.White)
      .width('60%')
      .height(50)
      .onChange((value: number) => {
        this.rate = value / 100
      })
      .position({ x: '20%', y: '80%' })
  }

  build() {
    Column() {
      Row() {
        Image($r("app.media.favorite"))
          .width(48)
          .height(48)
          .objectFit(ImageFit.Contain)
          .margin({ left: 12, right: 12 })
          .displayPriority(1)  // 布局優(yōu)先級

        Image($r("app.media.down"))
          .width(48)
          .height(48)
          .objectFit(ImageFit.Contain)
          .margin({ left: 12, right: 12 })
          .displayPriority(2)  // 布局優(yōu)先級

        Image($r("app.media.pause"))
          .width(48)
          .height(48)
          .objectFit(ImageFit.Contain)
          .margin({ left: 12, right: 12 })
          .displayPriority(3)  // 布局優(yōu)先級

        Image($r("app.media.next"))
          .width(48)
          .height(48)
          .objectFit(ImageFit.Contain)
          .margin({ left: 12, right: 12 })
          .displayPriority(2)  // 布局優(yōu)先級

        Image($r("app.media.list"))
          .width(48)
          .height(48)
          .objectFit(ImageFit.Contain)
          .margin({ left: 12, right: 12 })
          .displayPriority(1)  // 布局優(yōu)先級
      }
      .width(this.rate * 100 + '%')
      .height(96)
      .borderRadius(16)
      .backgroundColor('#FFFFFF')
      .justifyContent(FlexAlign.Center)
      .alignItems(VerticalAlign.Center)

      this.slider()
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F1F3F5')
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center)
  }
}

折行能力

折行能力通過使用 Flex折行布局 (將wrap屬性設(shè)置為FlexWrap.Wrap)實現(xiàn),當橫向布局尺寸不足以完整顯示內(nèi)容元素時,通過折行的方式,將元素顯示在下方。


示例圖
@Entry
@Component
struct WrapCapabilitySample {
  @State rate: number = 0.7
  readonly imageList: Resource [] = [
    $r('app.media.flexWrap1'),
    $r('app.media.flexWrap2'),
    $r('app.media.flexWrap3'),
    $r('app.media.flexWrap4'),
    $r('app.media.flexWrap5'),
    $r('app.media.flexWrap6')
  ]

  // 底部滑塊,可以通過拖拽滑塊改變?nèi)萜鞒叽?  @Builder slider() {
    Slider({ value: this.rate * 100, min: 50, max: 70, style: SliderStyle.OutSet })
      .blockColor(Color.White)
      .width('60%')
      .onChange((value: number) => {
        this.rate = value / 100
      })
      .position({ x: '20%', y: '87%' })
  }

  build() {
    Flex({ justifyContent: FlexAlign.Center, direction: FlexDirection.Column }) {
      Column() {
        // 通過Flex組件warp參數(shù)實現(xiàn)自適應(yīng)折行
        Flex({
          direction: FlexDirection.Row,
          alignItems: ItemAlign.Center,
          justifyContent: FlexAlign.Center,
          wrap: FlexWrap.Wrap
        }) {
          ForEach(this.imageList, (item:Resource) => {
            Image(item).width(183).height(138).padding(10)
          })
        }
        .backgroundColor('#FFFFFF')
        .padding(20)
        .width(this.rate * 100 + '%')
        .borderRadius(16)
      }
      .width('100%')

      this.slider()
    }.width('100%')
    .height('100%')
    .backgroundColor('#F1F3F5')
  }
}

這就是自適應(yīng)布局的7種能力,下面給出一個案例,主要是想讓大家知道這7種能力可以用在什么地方。


使用自適應(yīng)布局

上圖是一個音樂播放器,左邊是音樂播放器在平板上的顯示效果,中間是音樂播放器在手機上的顯示效果,右邊是音樂播放器在折疊屏上的顯示效果。我們把音樂播放器分為6個區(qū)域。

區(qū)域 布局能力 實現(xiàn)方案
1、標題欄 自適應(yīng)布局-拉伸能力 外層使用Row組件,內(nèi)層的留白組件自帶拉伸能力。
2、專輯圖片 自適應(yīng)布局-縮放能力 設(shè)置圖片aspectRatio屬性,將寬高比設(shè)置1:1。
3、收藏/下載/評論/分享 自適應(yīng)布局-均分能力 justifyContent屬性設(shè)置為FlexAlign.SpaceEvenly。
4、底部播放量 自適應(yīng)布局-占比能力 設(shè)置layoutWeight屬性,將左側(cè)與右側(cè)占比為3:1。
5、收藏/播放/上一首/下一首 自適應(yīng)布局-隱藏能力 設(shè)置優(yōu)先級displayPriority屬性,平板顯示5個按鈕,折疊屏顯示3個按鈕,手機顯示一個按鈕。
6、音樂列表 自適應(yīng)布局-延伸能力 設(shè)置lanes,列表顯示1列或者兩列。

響應(yīng)式布局

拉伸屏幕,頁面的位置關(guān)系發(fā)生變化。自適應(yīng)布局可以保證窗口尺寸在一定范圍內(nèi)變化時,頁面的顯示是正常的。但是將窗口尺寸變化較大時(如窗口寬度從400vp變化為1000vp),僅僅依靠自適應(yīng)布局可能出現(xiàn)圖片異常放大或頁面內(nèi)容稀疏、留白過多等問題,此時就需要借助響應(yīng)式布局能力調(diào)整頁面結(jié)構(gòu)。

斷點

將窗口寬度劃分為不同的范圍(即斷點),監(jiān)聽窗口尺寸變化,當斷點改變時同步調(diào)整頁面布局。斷點支持自定義,取值范圍可以修改,下標是4個常見斷點范圍。

名稱 取值范圍
xs(超小,智能穿戴類設(shè)備) [0, 320)
sm(小,手機) [320, 600)
xs(中等,折疊屏) [600, 840)
xs(大,平板) [840, +∞)

可以根據(jù)實際需要在lg斷點后面新增xl、xxl等斷點,但注意新增斷點會同時增加設(shè)計師及開發(fā)者的工作量。
系統(tǒng)提供了多種方法,判斷應(yīng)用當前處于何種斷點,進而可以調(diào)整應(yīng)用的布局。先介紹如何通過窗口對象監(jiān)聽斷點變化。
在UIAbility的onWindowStageCreate生命周期回調(diào)中,通過窗口對象獲取啟動時的應(yīng)用窗口寬度并注冊回調(diào)函數(shù)監(jiān)聽窗口尺寸變化。將窗口尺寸的長度單位由px換算為vp后,即可基于前文中介紹的規(guī)則得到當前斷點值,此時可以使用狀態(tài)變量記錄當前的斷點值方便后續(xù)使用。

// MainAbility.ts
import window from '@ohos.window'
import display from '@ohos.display'
import UIAbility from '@ohos.app.ability.UIAbility'

export default class MainAbility extends UIAbility {
  private windowObj?: window.Window
  private curBp: string = ''
  //...
  // 根據(jù)當前窗口尺寸更新斷點
  private updateBreakpoint(windowWidth: number) :void{
    // 將長度的單位由px換算為vp
    let windowWidthVp = windowWidth / display.getDefaultDisplaySync().densityPixels
    let newBp: string = ''
    if (windowWidthVp < 320) {
      newBp = 'xs'
    } else if (windowWidthVp < 600) {
      newBp = 'sm'
    } else if (windowWidthVp < 840) {
      newBp = 'md'
    } else {
      newBp = 'lg'
    }
    if (this.curBp !== newBp) {
      this.curBp = newBp
      // 使用狀態(tài)變量記錄當前斷點值
      AppStorage.setOrCreate('currentBreakpoint', this.curBp)
    }
  }

  onWindowStageCreate(windowStage: window.WindowStage) :void{
    windowStage.getMainWindow().then((windowObj) => {
      this.windowObj = windowObj
      // 獲取應(yīng)用啟動時的窗口尺寸
      this.updateBreakpoint(windowObj.getWindowProperties().windowRect.width)
      // 注冊回調(diào)函數(shù),監(jiān)聽窗口尺寸變化
      windowObj.on('windowSizeChange', (windowSize)=>{
        this.updateBreakpoint(windowSize.width)
      })
    });
   // ...
  }
  //...
}

在頁面中,獲取及使用當前的斷點。

@Entry
@Component
struct Index {
  @StorageProp('currentBreakpoint') curBp: string = 'sm'

  build() {
    Flex({justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center}) {
      Text(this.curBp).fontSize(50).fontWeight(FontWeight.Medium)
    }
    .width('100%')
    .height('100%')
  }
}

媒體查詢

媒體查詢提供了豐富的媒體特征監(jiān)聽能力,可以監(jiān)聽應(yīng)用顯示區(qū)域變化、橫豎屏、深淺色、設(shè)備類型等等,因此在應(yīng)用開發(fā)過程中使用的非常廣泛。下面通過通過媒體查詢,監(jiān)聽應(yīng)用窗口寬度變化,獲取當前應(yīng)用所處的斷點值。

export class BreakpointSystem {
  private currentBreakpoint: string = BreakpointConstants.BREAKPOINT_SM;
  // 監(jiān)聽sm的屏幕尺寸
  private smListener: mediaquery.MediaQueryListener = mediaquery.matchMediaSync(BreakpointConstants.RANGE_SM);
  // 監(jiān)聽md的屏幕尺寸
  private mdListener: mediaquery.MediaQueryListener = mediaquery.matchMediaSync(BreakpointConstants.RANGE_MD);
  // 監(jiān)聽lg的屏幕尺寸
  private lgListener: mediaquery.MediaQueryListener = mediaquery.matchMediaSync(BreakpointConstants.RANGE_LG);

  private updateCurrentBreakpoint(breakpoint: string): void {
    if (this.currentBreakpoint !== breakpoint) {
      this.currentBreakpoint = breakpoint;
      // 將斷點保存到AppStorage
      AppStorage.setOrCreate<string>(BreakpointConstants.CURRENT_BREAKPOINT, this.currentBreakpoint);
    }
  }

  private isBreakpointSM = (mediaQueryResult: mediaquery.MediaQueryResult): void => {
    if (mediaQueryResult.matches) {
      this.updateCurrentBreakpoint(BreakpointConstants.BREAKPOINT_SM);
    }
  }
  private isBreakpointMD = (mediaQueryResult: mediaquery.MediaQueryResult): void => {
    if (mediaQueryResult.matches) {
      this.updateCurrentBreakpoint(BreakpointConstants.BREAKPOINT_MD);
    }
  }
  private isBreakpointLG = (mediaQueryResult: mediaquery.MediaQueryResult): void => {
    if (mediaQueryResult.matches) {
      this.updateCurrentBreakpoint(BreakpointConstants.BREAKPOINT_LG);
    }
  }

  public register(): void {
    this.smListener = mediaquery.matchMediaSync(BreakpointConstants.RANGE_SM);
    this.smListener.on('change', this.isBreakpointSM);
    this.mdListener = mediaquery.matchMediaSync(BreakpointConstants.RANGE_MD);
    this.mdListener.on('change', this.isBreakpointMD);
    this.lgListener = mediaquery.matchMediaSync(BreakpointConstants.RANGE_LG);
    this.lgListener.on('change', this.isBreakpointLG);
  }

  public unregister(): void {
    this.smListener.off('change', this.isBreakpointSM);
    this.mdListener.off('change', this.isBreakpointMD);
    this.lgListener.off('change', this.isBreakpointLG);
  }
}

在上述代碼中,我們定義不同的屏幕尺寸監(jiān)聽,通過媒體查詢mediaquery.matchMediaSync來監(jiān)聽屏幕尺寸。將監(jiān)聽到的屏幕尺寸保存AppStorage,這樣其它頁面就能通過AppStorage獲取屏幕尺寸。同時提供注冊register方法和注銷unregister方法。

@Entry
@Component
struct MediaQuerySample {
  @StorageLink('currentBreakpoint') private currentBreakpoint: string = "md";
  private breakpointSystem: BreakpointSystem = new BreakpointSystem()

  aboutToAppear() {
    this.breakpointSystem.register()
  }

  aboutToDisappear() {
    this.breakpointSystem.unregister()
  }
  build() {
    Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
      Text(this.currentBreakpoint)
        .fontSize(24)
        .margin(10)
    }
    .width('100%')
    .height('100%')
  }
}

在上述代碼中,在aboutToAppear中注冊媒體查詢,在aboutToDisappear中注銷媒體查詢。由于斷點保存在AppStorage,所以可以直接使用@StorageLink裝飾器從AppStorage中取出斷點。

柵格布局

根據(jù)設(shè)備的寬度,將不同的屏幕尺寸劃分為不同數(shù)量的柵格,來實現(xiàn)屏幕的自適應(yīng)。如下圖,小尺寸的手機可以畫4個柵格,折疊屏可以畫8個柵格,平板可以畫12個柵格。一般來說,推薦按照4、8、12的比例進行柵格劃分。柵格和柵格之前有12vp的間距,如果沒有間距,柵格就會擠在一起。


示例圖

span用于設(shè)置柵格的數(shù)量,offset用于設(shè)置偏移量。如下圖,手機設(shè)置4個柵格,不設(shè)置偏移量。折疊屏總共有8個柵格,設(shè)置6個柵格,偏移1個柵格,就達到了居中的效果。平板總共有12個柵格,設(shè)置8個柵格,偏移2個柵格,就達到了居中的效果。


示例圖

下面的代碼就實現(xiàn)了上面所說的在不同設(shè)備上的登錄頁面。
build() {
    GridRow({
      /**
       * columns用于指定不同設(shè)備占據(jù)的總柵格數(shù),默認情況下,總柵格數(shù)為12
       * 指定手機的總柵格數(shù)為4,折疊屏總柵格數(shù)為8,平板總柵格數(shù)為12。
       */
      columns:{sm: 4, md: 8, lg: 12},
      // 間距
      gutter: 12
    }) {
      // 子組件
      GridCol({
        // 手機占4個柵格,折疊屏占8個柵,平板占12個柵格。
        span: {sm: 4, md: 6, lg: 8},
        // 手機不偏移,折疊屏偏移一個柵格,平板偏移2個柵格。
        offset: {sm: 0, md: 1, lg: 2}
      }) {
        // 登錄頁面
        this.loginUI()
      }
    }
  }

柵格組件提供了豐富的自定義能力,功能異常靈活和強大。只需要明確柵格在不同斷點下的Columns、Margin、Gutter及span等參數(shù),即可確定最終布局,無需關(guān)心具體的設(shè)備類型及設(shè)備狀態(tài)(如橫豎屏)等。以上只是簡單的介紹了下柵格布局,估計有人沒看懂,關(guān)于柵格布局的詳細文檔還請查看官方文檔。

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

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

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