HarmonyOS Developer 常见布局开发指导

丶龙八夷
发布于 2023-3-23 19:55
浏览
0收藏

自适应布局

线性布局

线性布局(LinearLayout)是开发中最常用的布局。线性布局的子组件在线性方向上(水平方向和垂直方向)依次排列。

通过线性容器​​Row​​​和​​Column​​实现线性布局。Column容器内子组件按照垂直方向排列,Row组件中,子组件按照水平方向排列。

线性布局的排列

线性布局的排列方向由所选容器组件决定。根据不同的排列方向,选择使用Row或Column容器创建线性布局,通过调整space,alignItems,justifyContent属性调整子组件的间距,水平垂直方向的对齐方式。

  1. 通过space参数设置主轴(排列方向)上子组件的间距。达到各子组件在排列方向上的等间距效果。
  2. 通过alignItems属性设置子组件在交叉轴(排列方向的垂直方向)的对齐方式。且在各类尺寸屏幕中,表现一致。其中,交叉轴为垂直方向时,取值为​​VerticalAlign类型​​​,水平方向取值为​​HorizontalAlign类型​​。
  3. 通过justifyContent属性设置子组件在主轴(排列方向)上的对齐方式。实现布局的自适应均分能力。取值为​​FlexAlign类型​​。

具体使用以及效果如下表所示:

属性名

描述

Row效果图

Column效果图

space

- 横向布局中各子组件的在水平方向的间距

- 纵向布局中个子组件垂直方向间距


HarmonyOS Developer 常见布局开发指导-鸿蒙开发者社区



HarmonyOS Developer 常见布局开发指导-鸿蒙开发者社区


alignItems

容器排列方向的垂直方向上,子组件在父容器中的对齐方式


HarmonyOS Developer 常见布局开发指导-鸿蒙开发者社区



HarmonyOS Developer 常见布局开发指导-鸿蒙开发者社区


justifyContent

容器排列方向上,子组件在父容器中的对齐方式


HarmonyOS Developer 常见布局开发指导-鸿蒙开发者社区



HarmonyOS Developer 常见布局开发指导-鸿蒙开发者社区


自适应拉伸

在线性布局下,常用空白填充组件​​Blank​​,在容器主轴方向自动填充空白空间,达到自适应拉伸效果。

@Entry
@Component
struct BlankExample {
  build() {
    Column() {
      Row() {
        Text('Bluetooth').fontSize(18)
        Blank()
        Toggle({ type: ToggleType.Switch, isOn: true })
      }.backgroundColor(0xFFFFFF).borderRadius(15).padding({ left: 12 }).width('100%')
    }.backgroundColor(0xEFEFEF).padding(20).width('100%')
  }
}

HarmonyOS Developer 常见布局开发指导-鸿蒙开发者社区

自适应缩放

自适应缩放是指在各种不同大小设备中,子组件按照预设的比例,尺寸随容器尺寸的变化而变化。在线性布局中有下列方法实现:

  1. 父容器尺寸确定时,设置了layoutWeight属性的子组件与兄弟元素占主轴尺寸按照权重进行分配,忽略元素本身尺寸设置,在任意尺寸设备下,自适应占满剩余空间。

@Entry
@Component
struct layoutWeightExample {
  build() {
    Column() {
      Text('1:2:3').width('100%')
      Row() {
        Column() {
          Text('layoutWeight(1)')
            .textAlign(TextAlign.Center)
        }.layoutWeight(2).backgroundColor(0xffd306).height('100%')

        Column() {
          Text('layoutWeight(2)')
            .textAlign(TextAlign.Center)
        }.layoutWeight(4).backgroundColor(0xffed97).height('100%')

        Column() {
          Text('layoutWeight(6)')
            .textAlign(TextAlign.Center)
        }.layoutWeight(6).backgroundColor(0xffd306).height('100%')

      }.backgroundColor(0xffd306).height('30%')

      Text('2:5:3').width('100%')
      Row() {
        Column() {
          Text('layoutWeight(2)')
            .textAlign(TextAlign.Center)
        }.layoutWeight(2).backgroundColor(0xffd306).height('100%')

        Column() {
          Text('layoutWeight(5)')
            .textAlign(TextAlign.Center)
        }.layoutWeight(5).backgroundColor(0xffed97).height('100%')

        Column() {
          Text('layoutWeight(3)')
            .textAlign(TextAlign.Center)
        }.layoutWeight(3).backgroundColor(0xffd306).height('100%')
      }.backgroundColor(0xffd306).height('30%')
    }
  }
}

HarmonyOS Developer 常见布局开发指导-鸿蒙开发者社区

  1. 父容器尺寸确定时,使用百分比设置子组件以及兄弟组件的width宽度,可以保证各自元素在任意尺寸下的自适应占比。

@Entry
@Component
struct WidthExample {
  build() {
    Column() {
      Row() {
        Column() {
          Text('left width 20%')
            .textAlign(TextAlign.Center)
        }.width('20%').backgroundColor(0xffd306).height('100%')

        Column() {
          Text('center width 50%')
            .textAlign(TextAlign.Center)
        }.width('50%').backgroundColor(0xffed97).height('100%')

        Column() {
          Text('right width 30%')
            .textAlign(TextAlign.Center)
        }.width('30%').backgroundColor(0xffd306).height('100%')
      }.backgroundColor(0xffd306).height('30%')
    }
  }
}

HarmonyOS Developer 常见布局开发指导-鸿蒙开发者社区

上例中,在任意大小的设备中,子组件的宽度占比固定。

定位能力
  • 相对定位
    使用组件的​​​offset属性​​可以实现相对定位,设置元素相对于自身的偏移量。设置该属性,不影响父容器布局,仅在绘制时进行位置调整。使用线性布局和offset可以实现大部分布局的开发。

上例中,在任意大小的设备中,子组件的宽度占比固定。

@Entry
@Component
struct OffsetExample {
  @Styles eleStyle() {
    .size({ width: 120, height: '50' })
    .backgroundColor(0xbbb2cb)
    .border({ width: 1 })
  }

  build() {
    Column({ space: 20 }) {
      Row() {
        Text('1').size({ width: '15%', height: '50' }).backgroundColor(0xdeb887).border({ width: 1 }).fontSize(16)
        Text('2  offset(15, 30)')
          .eleStyle()
          .fontSize(16)
          .align(Alignment.Start)
          .offset({ x: 15, y: 30 })
        Text('3').size({ width: '15%', height: '50' }).backgroundColor(0xdeb887).border({ width: 1 }).fontSize(16)
        Text('4 offset(-10%, 20%)')
          .eleStyle()
          .fontSize(16)
          .offset({ x: '-5%', y: '20%' })
      }.width('90%').height(150).border({ width: 1, style: BorderStyle.Dashed })
    }
    .width('100%')
    .margin({ top: 25 })
  }
} 

HarmonyOS Developer 常见布局开发指导-鸿蒙开发者社区

  • 绝对定位

线性布局中可以使用组件的​​positon属性​​实现绝对布局(AbsoluteLayout),设置元素左上角相对于父容器左上角偏移位置。对于不同尺寸的设备,使用绝对定位的适应性会比较差,在屏幕的适配上有缺陷。

@Entry
@Component
struct PositionExample {
  @Styles eleStyle(){
    .backgroundColor(0xbbb2cb)
    .border({ width: 1 })
    .size({ width: 120, height: 50 })
  }

  build() {
    Column({ space: 20 }) {
      // 设置子组件左上角相对于父组件左上角的偏移位置
      Row() {
        Text('position(30, 10)')
          .eleStyle()
          .fontSize(16)
          .position({ x: 10, y: 10 })

        Text('position(50%, 70%)')
          .eleStyle()
          .fontSize(16)
          .position({ x: '50%', y: '70%' })

        Text('position(10%, 90%)')
          .eleStyle()
          .fontSize(16)
          .position({ x: '10%', y: '80%' })
      }.width('90%').height('100%').border({ width: 1, style: BorderStyle.Dashed })
    }
    .width('90%').margin(25)
  }
}

HarmonyOS Developer 常见布局开发指导-鸿蒙开发者社区

自适应延伸

自适应延伸是在不同尺寸设备下,当页面显示内容个数不一并延伸到屏幕外时,可通过滚动条拖动展示。适用于线性布局中内容无法一屏展示的场景。常见以下两类实现方法。

  • List组件
    List子项过多一屏放不下时,未展示的子项通过滚动条拖动显示。通过scrollBar属性设置滚动条的常驻状态,edgeEffect属性设置拖动到极限的回弹效果。
    纵向List:

  @Entry
  @Component
  struct ListExample1 {
    @State arr: string[] = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"]
    @State alignListItem: ListItemAlign = ListItemAlign.Start
  
    build() {
      Column() {
        List({ space: 20, initialIndex: 0 }) {
          ForEach(this.arr, (item) => {
            ListItem() {
              Text('' + item)
                .width('100%')
                .height(100)
                .fontSize(16)
                .textAlign(TextAlign.Center)
                .borderRadius(10)
                .backgroundColor(0xFFFFFF)
            }
            .border({ width: 2, color: Color.Green })
          }, item => item)
        }
        .border({ width: 2, color: Color.Red, style: BorderStyle.Dashed })
        .scrollBar(BarState.On) // 滚动条常驻
        .edgeEffect(EdgeEffect.Spring) // 滚动到边缘再拖动回弹效果
  
      }.width('100%').height('100%').backgroundColor(0xDCDCDC).padding(20)
    }
  }

HarmonyOS Developer 常见布局开发指导-鸿蒙开发者社区

横向List:

 @Entry
  @Component
  struct ListExample2 {
    @State arr: string[] = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"]
    @State alignListItem: ListItemAlign = ListItemAlign.Start
  
    build() {
      Column() {
        List({ space: 20, initialIndex: 0 }) {
          ForEach(this.arr, (item) => {
            ListItem() {
              Text('' + item)
                .height('100%')
                .width(100)
                .fontSize(16)
                .textAlign(TextAlign.Center)
                .borderRadius(10)
                .backgroundColor(0xFFFFFF)
            }
            .border({ width: 2, color: Color.Green })
          }, item => item)
        }
        .border({ width: 2, color: Color.Red, style: BorderStyle.Dashed })
        .scrollBar(BarState.On) // 滚动条常驻
        .edgeEffect(EdgeEffect.Spring) // 滚动到边缘再拖动回弹效果
        .listDirection(Axis.Horizontal)  // 列表水平排列
      }.width('100%').height('100%').backgroundColor(0xDCDCDC).padding(20)
    }
  } 

HarmonyOS Developer 常见布局开发指导-鸿蒙开发者社区

  • Scroll组件

线性布局中,当子组件的布局尺寸超过父组件的尺寸时,内容可以滚动。在Column或者Row外层包裹一个可滚动的容器组件Scroll实现。

纵向Scroll:

@Entry
@Component
struct ScrollExample {
  scroller: Scroller = new Scroller();
  private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

  build() {
    Scroll(this.scroller) {
      Column() {
        ForEach(this.arr, (item) => {
          Text(item.toString())
            .width('90%')
            .height(150)
            .backgroundColor(0xFFFFFF)
            .borderRadius(15)
            .fontSize(16)
            .textAlign(TextAlign.Center)
            .margin({ top: 10 })
        }, item => item)
      }.width('100%')
    }
    .backgroundColor(0xDCDCDC)
    .scrollable(ScrollDirection.Vertical) // 滚动方向纵向
    .scrollBar(BarState.On) // 滚动条常驻显示
    .scrollBarColor(Color.Gray) // 滚动条颜色
    .scrollBarWidth(30) // 滚动条宽度
    .edgeEffect(EdgeEffect.Spring) // 滚动到边沿后回弹
  }
}

HarmonyOS Developer 常见布局开发指导-鸿蒙开发者社区

横向Scroll:

@Entry
@Component
struct ScrollExample {
  scroller: Scroller = new Scroller();
  private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

  build() {
    Scroll(this.scroller) {
      Row() {
        ForEach(this.arr, (item) => {
          Text(item.toString())
            .height('90%')
            .width(150)
            .backgroundColor(0xFFFFFF)
            .borderRadius(15)
            .fontSize(16)
            .textAlign(TextAlign.Center)
            .margin({ left: 10 })
        }, item => item)
      }.height('100%')
    }
    .backgroundColor(0xDCDCDC)
    .scrollable(ScrollDirection.Horizontal) // 滚动方向横向
    .scrollBar(BarState.On) // 滚动条常驻显示
    .scrollBarColor(Color.Gray) // 滚动条颜色
    .scrollBarWidth(30) // 滚动条宽度
    .edgeEffect(EdgeEffect.Spring) // 滚动到边沿后回弹
  }
}

HarmonyOS Developer 常见布局开发指导-鸿蒙开发者社区

层叠布局

层叠布局(StackLayout)用于在屏幕上预留一块区域来显示组件中的元素,提供元素可以重叠的布局。

通过层叠容器​​Stack​​实现,容器中的子元素依次入栈,后一个子元素覆盖前一个子元素显示。

对齐方式

设置子元素在容器内的对齐方式。支持左上,上中,右上,左,中,右,右下,中下,右下九种对齐方式,如下表所示:

名称

描述

图示

TopStart

顶部起始端

HarmonyOS Developer 常见布局开发指导-鸿蒙开发者社区

Top

顶部横向居中

HarmonyOS Developer 常见布局开发指导-鸿蒙开发者社区

TopEnd

顶部尾端

HarmonyOS Developer 常见布局开发指导-鸿蒙开发者社区

Start

起始端纵向居中

HarmonyOS Developer 常见布局开发指导-鸿蒙开发者社区

Center

横向和纵向居中

HarmonyOS Developer 常见布局开发指导-鸿蒙开发者社区

End

尾端纵向居中

HarmonyOS Developer 常见布局开发指导-鸿蒙开发者社区

BottomStart

底部起始端

HarmonyOS Developer 常见布局开发指导-鸿蒙开发者社区

Bottom

底部横向居中

HarmonyOS Developer 常见布局开发指导-鸿蒙开发者社区

BottomEnd

底部尾端

HarmonyOS Developer 常见布局开发指导-鸿蒙开发者社区

Z序控制

Stack容器中兄弟组件显示层级关系可以通过​​zIndex​

属性改变。zIndex值越大,显示层级越高,即zIndex值大的组件会覆盖在zIndex值小的组件上方。

  • 在层叠布局中,如果后面子元素尺寸大于前面子元素尺寸,则前面子元素完全隐藏。

Stack({ alignContent: Alignment.BottomStart }) {
    Column() {
      Text('Stack子元素1').textAlign(TextAlign.End).fontSize(20)
    }.width(100).height(100).backgroundColor(0xffd306)
    Column() {
      Text('Stack子元素2').fontSize(20)
    }.width(150).height(150).backgroundColor(Color.Pink)
    Column() {
      Text('Stack子元素3').fontSize(20)
    }.width(200).height(200).backgroundColor(Color.Grey)
}.margin({ top: 100 }).width(350).height(350).backgroundColor(0xe0e0e0)

HarmonyOS Developer 常见布局开发指导-鸿蒙开发者社区

上图中,最后的子元素3的尺寸大于前面的所有子元素,所以,前面两个元素完全隐藏。改变子元素1,子元素2的zIndex属性后,可以将元素展示出来。

Stack({ alignContent: Alignment.BottomStart }) {
    Column() {
      Text('Stack子元素1').fontSize(20)
    }.width(100).height(100).backgroundColor(0xffd306).zIndex(2)
    Column() {
      Text('Stack子元素2').fontSize(20)
    }.width(150).height(150).backgroundColor(Color.Pink).zIndex(1)
    Column() {
      Text('Stack子元素3').fontSize(20)
    }.width(200).height(200).backgroundColor(Color.Grey)
}.margin({ top: 100 }).width(350).height(350).backgroundColor(0xe0e0e0)

HarmonyOS Developer 常见布局开发指导-鸿蒙开发者社区

网格布局

网格布局(GridLayout)是自适应布局中一种重要的布局,具备较强的页面均分能力,子组件占比控制能力。

通过​​Grid​​​容器组件和子组件​​GridItem​​实现,

Grid用于设置网格布局相关参数,GridItem定义子组件相关特征。优势如下:

  1. 容器组件尺寸发生变化时,所有子组件以及间距等比例调整,实现布局的自适应能力。
  2. 支持自定义网格布局行数和列数,以及每行每列尺寸占比。
  3. 支持设置网格布局中子组件的行列间距。
  4. 支持设置子组件横跨几行或者几列。

容器组件Grid设置

行列数量占比

通过Grid的组件的columnsTemplate和rowTemplate属性设置网格布局行列数量与尺寸占比。

下面以columnsTemplate为例,介绍该属性的设置,该属性值是一个由多个空格和'数字+fr'间隔拼接的字符串,fr的个数即网格布局的列数,fr前面的数值大小,用于计算该列在网格布局宽度上的占比,最终决定该列的宽度。

struct GridExample {
  @State Number: Array<string> = ['1', '2', '3', '4']

  build() {
    Column({ space: 5 }) {
      Grid() {
        ForEach(this.Number, (num: string) => {
          GridItem() {
            Text(`列${num}`)
              .fontSize(16)
              .textAlign(TextAlign.Center)
              .backgroundColor(0xd0d0d0)
              .width('100%')
              .height('100%')
              .borderRadius(5)
          }
        })
      }
      .columnsTemplate('1fr 1fr 1fr 1fr')
      .rowsTemplate('1fr')
      .columnsGap(10)
      .rowsGap(20)
      .width('90%')
      .backgroundColor(0xF0F0F0)
      .height(100)
    }.width('100%')
  }
}

定义了四个等分的列,每列宽度相等。

struct GridExample {
  @State Number: Array<string> = ['1', '2', '3', '4']

  build() {
    Column({ space: 5 }) {
      Grid() {
        ForEach(this.Number, (num: string) => {
          GridItem() {
            Text(`列${num}`)
              .fontSize(16)
              .textAlign(TextAlign.Center)
              .backgroundColor(0xd0d0d0)
              .width('100%')
              .height('100%')
              .borderRadius(5)
          }
        })
      }
      .columnsTemplate('1fr 2fr 3fr 4fr')
      .rowsTemplate('1fr')
      .columnsGap(10)
      .rowsGap(20)
      .width('90%')
      .backgroundColor(0xF0F0F0)
      .height(100)
    }.width('100%')
  }
}

定义了四列,每列宽度比值为1:2:3:4。

struct GridExample {
  @State Number: Array<string> = ['1', '2', '3']

  build() {
    Column({ space: 5 }) {
      Grid() {
        ForEach(this.Number, (num: string) => {
          GridItem() {
            Text(`列${num}`)
              .fontSize(16)
              .textAlign(TextAlign.Center)
              .backgroundColor(0xd0d0d0)
              .width('100%')
              .height('100%')
              .borderRadius(5)
          }
        })
      }
      .columnsTemplate('4fr 2fr 3fr')
      .rowsTemplate('1fr')
      .columnsGap(10)
      .rowsGap(20)
      .width('90%')
      .backgroundColor(0xF0F0F0)
      .height(100)
    }.width('100%')
  }
}

定义了三列,每列宽度比值为4:2:3。

效果如下:

HarmonyOS Developer 常见布局开发指导-鸿蒙开发者社区

排列方式

通过layoutDirection可以设置网格布局的主轴方向,决定子组件的排列方式。

可选值包括Row,RowReverse, Column, ColumnReverse四种情况。

效果如下:

HarmonyOS Developer 常见布局开发指导-鸿蒙开发者社区

行列间距

columnsGap用于设置网格子组件GridItem垂直方向的间距,rowsGap用于设置GridItem水平方向的间距。

Grid()
.columnsTemplate('1fr 1fr 1fr 1fr')
.columnsGap(10)
.rowsGap(20)

HarmonyOS Developer 常见布局开发指导-鸿蒙开发者社区

上图中,设置网格布局子组件间的垂直间距为20,水平间距为10。

网格子组件GridItem设置

设置子组件占的行列数

网格布局的行列标号从1开始,依次编号。

子组件横跨多行时,通过rowStart设置子组件起始行编号,rowEnd设置终点行编号。当rowStart值与rowEnd值相同时,子组件只占一个网格。示例如下:

Grid() {
    GridItem() {
      Text('5')
        .fontSize(16)
        .textAlign(TextAlign.Center)
        .textStyle()
    }.rowStart(2).rowEnd(3)  // 5子组件从第二行到第三行

    GridItem() {
      Text('4')
        .fontSize(16)
        .textAlign(TextAlign.Center)
        .textStyle()
    }.columnStart(4).columnEnd(5) // 4从第四列到第五列
  
    GridItem() {
      Text('6')
        .fontSize(16)
        .textAlign(TextAlign.Center)
        .textStyle()
    }.columnStart(2).columnEnd(4)  // 6从第二列到第四列

    GridItem() {
      Text('9')
        .fontSize(16)
        .textAlign(TextAlign.Center)
        .textStyle()
    }.columnStart(3).columnEnd(4)    // 从第三列到第四列
}
.columnsTemplate('1fr 1fr 1fr 1fr 1fr')
.rowsTemplate('1fr 1fr 1fr')
.columnsGap(10)
.rowsGap(20)
.width('90%')
.backgroundColor(0xF0F0F0)
.height('200vp')
.layoutDirection(GridDirection.Column)

HarmonyOS Developer 常见布局开发指导-鸿蒙开发者社区

场景示例

使用grid布局实现一个计算器的排布效果,代码如下:

@Entry
@Component
struct GridExample {
  @State Number: Array<string> = ['1', '2', '3', '+', '4', '5', '6', '-', '7', '8', '9', '*', '0', '.', '/']

  @Styles textStyle(){
    .backgroundColor(0xd0d0d0)
    .width('100%')
    .height('100%')
    .borderRadius(5)
  }

  build() {
    Column({ space: 5 }) {
      Grid() {
        GridItem() {
          Text('0')
            .fontSize(30)
            .textStyle()
        }.columnStart(1).columnEnd(4)

        GridItem() {
          Text('清空')
            .fontSize(16)
            .textAlign(TextAlign.Center)
            .textStyle()
        }.columnStart(1).columnEnd(2)

        GridItem() {
          Text('回退')
            .fontSize(16)
            .textAlign(TextAlign.Center)
            .textStyle()
        }.columnStart(3).columnEnd(4)

        ForEach(this.Number, (day: string) => {
          if (day === '0') {
            GridItem() {
              Text(day)
                .fontSize(16)
                .textAlign(TextAlign.Center)
                .textStyle()
            }.columnStart(1).columnEnd(2)
          } else {
            GridItem() {
              Text(day)
                .fontSize(16)
                .textAlign(TextAlign.Center)
                .textStyle()
            }
          }
        })
      }
      .columnsTemplate('1fr 1fr 1fr 1fr')
      .rowsTemplate('2fr 1fr 1fr 1fr 1fr 1fr')
      .columnsGap(10)
      .rowsGap(15)
      .width('90%')
      .backgroundColor(0xF0F0F0)
      .height('70%')
    }.width('100%').margin({ top: 5 })
  }
}

在大屏设备上展示效果如下:

HarmonyOS Developer 常见布局开发指导-鸿蒙开发者社区

在小屏设备下展示效果如下:

HarmonyOS Developer 常见布局开发指导-鸿蒙开发者社区




文章转载自:​​https://developer.harmonyos.com/cn/docs/documentation/doc-guides-V3/ui-ts-layout-linear-0000001478061513-V3?catalogVersion=V3​

标签
收藏
回复
举报
回复
    相关推荐