探究鸿蒙OS-Next版本中各种布局

177 阅读7分钟

最近闲下来,开始学习有关鸿蒙的知识,以下是本人在学习中对鸿蒙存在的各种布局进行学习探究。

1.线性布局

1.1 Row组件

struct Demo1 {
  @State message: string = 'Hello World'

  build() {
    Row() {
      Row() {
        Column().width(100).height(200).backgroundColor(Color.Red)
        Column().width(100).height(200).backgroundColor(Color.Blue)
        Column().width(100).height(200).backgroundColor(Color.Pink)
      }.width('100%').justifyContent(FlexAlign.SpaceEvenly)
    }
    .height('100%')
  }
}

如果row组件套row组件会默认居中,需要加上.alignItems(VerticalAlign.Top)

@Entry
@Component
struct Demo1 {
  @State message: string = 'Hello World'

  build() {
    Row() {
      Row() {
        Column().width(100).height(200).backgroundColor(Color.Red)
        Column().width(100).height(200).backgroundColor(Color.Blue)
        Column().width(100).height(200).backgroundColor(Color.Pink)
      }.width('100%').justifyContent(FlexAlign.SpaceEvenly)
    }
    .height('100%').alignItems(VerticalAlign.Top)
  }
}

1.2 Column组件

@Entry
@Component
struct Demo1 {
  @State message: string = 'Hello World'

  build() {
    Column() {
      Row() {
        Column().width(100).height(200).backgroundColor(Color.Red)
        Column().width(100).height(200).backgroundColor(Color.Blue)
        Column().width(100).height(200).backgroundColor(Color.Pink)
      }.width('100%').justifyContent(FlexAlign.SpaceEvenly).height(200)
      Column(){
        Column().width(200).height(100).backgroundColor(Color.Red)
        Column().width(200).height(100).backgroundColor(Color.Blue)
        Column().width(200).height(100).backgroundColor(Color.Yellow)
      }.height(100)
    }
    .height('100%').padding({
      top:20
    })
  }
}

注意 :在使用Row中写组件会导致内部的组件相互遮挡,如下图:上面的是Row嵌套下面的用Column嵌套

2.弹性布局

2.1Flex定义

Flex 布局 中,有两个重要的概念:主轴和交叉轴。

  • 主轴:就像一条基准线,决定了子元素排列的方向。子元素默认会沿着这条主轴一个接一个排开。主轴的起点是开始的位置,终点是结束的位置。
  • 交叉轴:和主轴垂直,是另一条基准线。交叉轴的起点和终点,分别是它的开始和结束位置。

简单来说,主轴是控制子元素横着排还是竖着排的轴线,而交叉轴就是和主轴垂直的那条轴线

与线性布局相比,它支持换行,但是没有滚动条

2.2Flex使用

@Entry
@Component
struct Page {
  @State message: string = 'Hello World';

  build() {
    Flex({
      direction: FlexDirection.Row,
      wrap:FlexWrap.Wrap
    }) {
      Row()
        .width(100)
        .height(50)
        .backgroundColor(Color.Red).margin({
        bottom:10,
        right:10,
        left:10
      })
      Row()
        .width(100)
        .height(50)
        .backgroundColor(Color.Red).margin({
        bottom:10,
        right:10,
        left:10
      })
      Row()
        .width(100)
        .height(50)
        .backgroundColor(Color.Red).margin({
        bottom:10,
        right:10,
        left:10
      })
      Row()
        .width(100)
        .height(50)
        .backgroundColor(Color.Red).margin({
        bottom:10,
        right:10,
        left:10
      })
      Row()
        .width(100)
        .height(50)
        .backgroundColor(Color.Red).margin({
        bottom:10,
        right:10,
        left:10
      })
      Row()
        .width(100)
        .height(50)
        .backgroundColor(Color.Red).margin({
        bottom:10,
        right:10,
        left:10
      })
    }.backgroundColor(Color.Yellow).width("100%").height('100%')
  }
}

3.相对布局

RelativeContainer为采用相对布局的容器,支持容器内部的子元素设置相对位置关系,适用于界面复杂场景的情况,对多个子组件进行对齐和排列。它具备以下特点

  • 锚点布局
  • 元素可以通过相对于父容器或其他兄弟元素的锚点来指定位置。
  • 使用锚点属性(如 startToStartOfendToEndOf)进行位置定义。
  • 父容器的默认 ID 是 "__Container__",你可以用它作为锚点的参考。
  • 唯一 ID
  • 每个子元素需要一个唯一的 ID,用于引用和定位。没有 ID 的元素无法参与相对定位。
  • 灵活性
  • 支持复杂的相对位置设置,例如对齐到左、右、上、下、中心等。
  • 提供了自由设计布局的能力,适用于动态或复杂的 UI 场景。

3.1 RelativeContainer定义

@Entry
@Component
struct RelativeContainerCase {

  build() {
    Column() {
      RelativeContainer() {
        Text("card1")
          .fontSize(25)
          .width(160)
          .height(150)
          .textAlign(TextAlign.End)
          .backgroundColor(Color.Green)

        Text("card2")
          .fontSize(25)
          .width(90)
          .height(130)
          .backgroundColor(Color.Yellow)
        Text("card3")
          .fontSize(25)
          .backgroundColor(Color.Red)

      } .width("100%")
      .height(190)
      .backgroundColor(Color.Blue)

    } .size({width: "100%", height: "100%"})
    .backgroundColor(Color.Orange)
    .padding(10)
  }
}

3.2 RelativeContainer对齐规则

RelativeContainer对子组件的对齐方式分为水平方向和竖直方向:

  • 垂直方向对齐:可选择 VerticalAlign.Top(顶部对齐)、VerticalAlign.Center(垂直居中)和 VerticalAlign.Bottom(底部对齐)。
  • 水平方向对齐:可选择 HorizontalAlign.Start(左对齐)、HorizontalAlign.Center(水平居中)和 HorizontalAlign.End(右对齐)。

3.2.1垂直方向对齐

@Entry
@Component
struct RelativeContainerRuleCase {
  build() {
   Row(){
     Column(){
       RelativeContainer() {
         //当前元素的竖直方向的上边对应描点容器的上边
         Text("Top-Top").backgroundColor(Color.Red).width(150).height(50).fontColor("#ffffff").alignRules({
           top:{anchor:"__container__",align:VerticalAlign.Top}
         })
         //当前元素的竖直方向的上边对应描点容器的中间
         Text("Top-Center").backgroundColor(Color.Red).width(150).height(50).fontColor("#ffffff").alignRules({
           top:{anchor:"__container__",align:VerticalAlign.Center}
         })
         //当前元素的竖直方向的上边对应描点容器的下边
         Text("Top-Bottom").backgroundColor(Color.Red).width(150).height(50).fontColor("#ffffff").alignRules({
           top:{anchor:"__container__",align:VerticalAlign.Bottom}
         })

         //当前元素的竖直方向的中间对应描点容器的上边
         Text("Center-Top").backgroundColor(Color.Orange).width(150).height(50).fontColor("#ffffff").alignRules({
           center:{anchor:"__container__",align:VerticalAlign.Top}
         })
         //当前元素的竖直方向的中间对应描点容器的中间
         Text("Center-Center").backgroundColor(Color.Orange).width(150).height(50).fontColor("#ffffff").alignRules({
           center:{anchor:"__container__",align:VerticalAlign.Center}
         })
         //当前元素的竖直方向的中间对应描点容器的下边
         Text("Center-Bottom").backgroundColor(Color.Orange).width(150).height(50).fontColor("#ffffff").alignRules({
           center:{anchor:"__container__",align:VerticalAlign.Bottom}
         })
         //当前元素的竖直方向的下边对应描点容器的上边
         Text("Bottom-Top").backgroundColor(Color.Blue).width(150).height(50).fontColor("#ffffff").alignRules({
           bottom:{anchor:"__container__",align:VerticalAlign.Top}
         })
         //当前元素的竖直方向的下边对应描点容器的中间
         Text("Bottom-Center").backgroundColor(Color.Blue).width(150).height(50).fontColor("#ffffff").alignRules({
           bottom:{anchor:"__container__",align:VerticalAlign.Center}
         })
         //当前元素的竖直方向的下边对应描点容器的下边
         Text("Bottom-Bottom").backgroundColor(Color.Blue).width(150).height(50).fontColor("#ffffff").alignRules({
           bottom:{anchor:"__container__",align:VerticalAlign.Bottom}
         })
       }
       .height(300)
       .width('100%').backgroundColor(Color.Pink)
     }.width("100%")
   }.height("100%")
  }
}

3.2.2 水平方向对齐

@Entry
@Component
struct RelativeContainerRuleCase2 {
  @State message: string = 'Hello World';

  build() {
    Row() {
      Column() {
        RelativeContainer() {
          //当前元素的左边与锚点元素的左边起始位置对齐
          Text("Left-Start").width(100).height(50).fontColor("#fff").backgroundColor(Color.Green).alignRules({
            left:{anchor:"__container__",align:HorizontalAlign.Start}
          })
          //当前元素的左边与锚点元素的中间位置对齐
          Text("Left-Center").width(100).height(50).fontColor("#fff").backgroundColor(Color.Green).alignRules({
            left:{anchor:"__container__",align:HorizontalAlign.Center}
          })
          //当前元素的左边与锚点元素的右边结束位置对齐
          Text("Left-End").width(100).height(50).fontColor("#fff").backgroundColor(Color.Green).alignRules({
            left:{anchor:"__container__",align:HorizontalAlign.End},

          })
          //当前元素的中间位置与锚点元素的左边起始位置对齐
          Text("Middle-Start").width(100).height(50).fontColor("#fff").backgroundColor(Color.Blue).alignRules({
            middle:{anchor:"__container__",align:HorizontalAlign.Start},
            center:{anchor:"__container__",align:VerticalAlign.Center}
          })
          //当前元素的中间位置与锚点元素的中间位置对齐
          Text("Middle-Center").width(100).height(50).fontColor("#fff").backgroundColor(Color.Blue).alignRules({
            middle:{anchor:"__container__",align:HorizontalAlign.Center},
            center:{anchor:"__container__",align:VerticalAlign.Center}
          })
          //当前元素的中间位置与锚点元素的右边结束位置对齐
          Text("Middle-End").width(100).height(50).fontColor("#fff").backgroundColor(Color.Blue).alignRules({
            middle:{anchor:"__container__",align:HorizontalAlign.End},
            center:{anchor:"__container__",align:VerticalAlign.Center}
          })
          //当前元素的右边与锚点元素的左边起始位置对齐
          Text("Right-Start").width(100).height(50).textAlign(TextAlign.End).fontColor("#fff").backgroundColor(Color.Red).alignRules({
            right:{anchor:"__container__",align:HorizontalAlign.Start},
            bottom:{anchor:"__container__",align:VerticalAlign.Bottom},

          })
          //当前元素的右边与锚点元素的中间位置对齐
          Text("Right-Center").width(100).height(50).textAlign(TextAlign.End).fontColor("#fff").backgroundColor(Color.Red).alignRules({
            right:{anchor:"__container__",align:HorizontalAlign.Center},
            bottom:{anchor:"__container__",align:VerticalAlign.Bottom},

          })
          //当前元素的右边与锚点元素的右边结束位置对齐
          Text("Right-End").width(100).height(50).textAlign(TextAlign.End).fontColor("#fff").backgroundColor(Color.Red).alignRules({
            right:{anchor:"__container__",align:HorizontalAlign.End},
            bottom:{anchor:"__container__",align:VerticalAlign.Bottom},

          })
        }.width("60%").height(400).backgroundColor(Color.Pink)
      }.width("100%")
    }.height("100%")
  }
}

4.堆叠布局

4.1子组件层级控制

Stack容器中⼦组件的层级除了可按照添加顺序决定,还能通过 Index 的值越⼤,层级越⾼

4.2 案例

import { promptAction } from '@kit.ArkUI';

@Entry
  @Component
  struct StackCase {
    @State content: string = '';

    searchContent() {
      promptAction.showToast({
        message: this.content
      })
    }

    enabledChange() {
      return this.content !== ""
    }

    build() {
      Column(){
        Image($r("app.media.baidu")).height(200).width("100%")
        Row() {
          Stack() {
            TextInput({ placeholder: "请输入需要搜索的内容", text: $$this.content })
              .width("100%")
              .height(40)
              .position({ x: 0, y: 0 })
              .zIndex(1)
              .borderRadius({
                topLeft: 10,
                topRight: 0,
                bottomLeft: 10,
                bottomRight: 0
              }).padding({
                right:60
              })
            Image($r("app.media.microphone")).height(20).width(20).position({ x: 200, y: 10 }).zIndex(2)
            Image($r("app.media.camera")).height(20).width(20).position({ x: 230, y: 10 }).zIndex(2)
          }.width(260).height("100%")

          Button("百度一下")
            .borderRadius({
              topLeft: 0,
              topRight: 10,
              bottomLeft: 0,
              bottomRight: 10
            })
            .layoutWeight(1)
            .height("100%").type(ButtonType.Normal)
            .onClick(() => {
              this.searchContent()
            })
            .enabled(this.enabledChange())
        }.width("100%").height(40)
      }.alignItems(HorizontalAlign.Center).width("100%").padding(10)

    }
  }

5.grid布局

5.1grid布局的使用

官网

  1. Grid可以设置columnsTemplate和rowsTemplate
  2. columnsTemplate是设置横向的分配,如果设置1fr 1fr表示,等分为两份,如果设置1fr 2fr表示左边一份,右边一份
  3. 在设置columnsTemplate不设置rowsTemplate的情况下,如果内容超出容器区域,会自动出现滚动条
  4. columnsGap设置列和列之间的间距,rowsGap设置行和行之间的间距
  5. Grid布局具有滚动条

5.2案例

@Entry
@Component
struct GridCase {
  @State message: string = 'Hello World';
  @State services: Array<string> = []

  build() {
    Grid() {
      GridCaseItem()
      GridCaseItem()
      GridCaseItem()
      GridCaseItem()
      GridCaseItem()
      GridCaseItem()
      GridCaseItem()
      GridCaseItem()
      GridCaseItem()
      GridCaseItem()
      GridCaseItem()
      GridCaseItem()
      GridCaseItem()
      GridCaseItem()
      GridCaseItem()
      GridCaseItem()
    }
    .width('100%')
    .height("100%")
    .columnsTemplate("1fr 1fr")
    .columnsGap(10)
    .rowsGap(10).padding(10)
  }
}

@Component
struct GridCaseItem {
  build() {
    GridItem() {
      Row() {
        Text("内容").width('100%').textAlign(TextAlign.Center)
      }.height(200).borderRadius(4).backgroundColor(Color.Pink)
    }
  }
}

链接