元服务——2、页面与基础布局

2024-11-27 21:28:56
18次阅读
0个评论

第二章 页面与布局

页面创建

新项目的创建

image-20241105195301725.png

再次进行【注册应用 ID】的创建

image-20241105195635547.png

修改名称后确认创建

image-20241105195833127.png

完成初始设置后,可以看到仅有一个 page 的 index.ets 页面

image-20241105200010903.png

我们已经有了第一页面,我们继续创建一个页面。

操作步骤【pages(鼠标右键)>New>ArkTS File】

image-20241105201750615.png

输入ArkTS File名称

image-20241105201932158.png

创建完毕效果

image-20241105202026553.png

这里将【Index.ets】的内容赋值到【SecondPage.ets】中,改一下结构体名称与message的字符串。

image-20241105202631286.png

现在我们已经有了两个页面了。

router 路由

路由概述

路由用于管理应用程序中的不同页面或者视图之间的导航。它就像是一张地图,指引用户(或者应用内部的逻辑)从一个地方(页面)到另一个地方。路由系统通常由一系列的路由规则组成,这些规则定义了 URL 路径(在 Web 应用中)或者某种导航标识符(在非 Web 应用中,如移动应用)与对应的组件或者页面之间的关联,在HarmonyOS开发中一般页面路由在src > main > resources > base > main_pages.json中设置。

使用路由

我们将页面的信息都写到【src>main>resources>base>main_pages.json】中。

image-20241105203325240.png

添加路由跳转代码

页面1:index.ets

import { authentication } from '@kit.AccountKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { router } from '@kit.ArkUI'

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

  build() {
    RelativeContainer() {
      Text(this.message)
        .id('HelloWorld')
        .fontSize(50)
        .fontWeight(FontWeight.Bold)
        .alignRules({
          center: { anchor: '__container__', align: VerticalAlign.Center },
          middle: { anchor: '__container__', align: HorizontalAlign.Center }
        })
      Button("跳转第二页").width('100%').height(80).onClick((event: ClickEvent) => {
        router.pushUrl({ url: 'pages/SecondPage' })
      }).margin({ top: 200 })
    }
    .height('100%')
    .width('100%')
  }

  aboutToAppear() {
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
    this.loginWithHuaweiID();
  }

  /**
   * Sample code for using HUAWEI ID to log in to atomic service.
   * According to the Atomic Service Review Guide, when a atomic service has an account system,
   * the option to log in with a HUAWEI ID must be provided.
   * The following presets the atomic service to use the HUAWEI ID silent login function.
   * To enable the atomic service to log in successfully using the HUAWEI ID, please refer
   * to the HarmonyOS HUAWEI ID Access Guide to configure the client ID and fingerprint certificate.
   */
  private loginWithHuaweiID() {
    // Create a login request and set parameters
    let loginRequest = new authentication.HuaweiIDProvider().createLoginWithHuaweiIDRequest();
    // Whether to forcibly launch the HUAWEI ID login page when the user is not logged in with the HUAWEI ID
    loginRequest.forceLogin = false;
    // Execute login request
    let controller = new authentication.AuthenticationController();
    controller.executeRequest(loginRequest).then((data) => {
      let loginWithHuaweiIDResponse = data as authentication.LoginWithHuaweiIDResponse;
      let authCode = loginWithHuaweiIDResponse.data?.authorizationCode;
      // Send authCode to the backend in exchange for unionID, session

    }).catch((error: BusinessError) => {
      hilog.error(0x0000, 'testTag', 'error: %{public}s', JSON.stringify(error));
      if (error.code == authentication.AuthenticationErrorCode.ACCOUNT_NOT_LOGGED_IN) {
        // HUAWEI ID is not logged in, it is recommended to jump to the login guide page

      }
    });
  }
}

页面2:SecondPage.ets

import { router } from '@kit.ArkUI'

@Entry
@Component
struct SecondPage {
  @State message: string = '第二个页面';

  build() {
    RelativeContainer() {
      Text(this.message)
        .id('SecondPage')
        .fontSize(50)
        .fontWeight(FontWeight.Bold)
        .alignRules({
          center: { anchor: '__container__', align: VerticalAlign.Center },
          middle: { anchor: '__container__', align: HorizontalAlign.Center }
        })
      Button("跳转第一页").width('100%').height(80).onClick((event: ClickEvent) => {
        router.pushUrl({ url: 'pages/Index' })
      }).margin({ top: 200 })
    }
    .height('100%')
    .width('100%')
  }
}

效果:

image-20241105204646680.png

image-20241105204711951.png

页面相互跳转完毕。

布局

布局概述

组件按照布局的要求依次排列,构成应用的页面。在声明式UI中,所有的页面都是由自定义组件构成,开发者可以根据自己的需求,选择合适的布局进行页面开发。

布局指用特定的组件或者属性来管理用户页面所放置UI组件的大小和位置。在实际的开发过程中,需要遵守以下流程保证整体的布局效果:

  • 确定页面的布局结构。

  • 分析页面中的元素构成。

  • 选用适合的布局容器组件或属性控制页面中各个元素的位置和大小。

布局结构

布局通常为分层结构,一个常见的页面结构如下所示:

image-20241105232238776.png

为实现上述效果,开发者需要在页面中声明对应的元素。其中,Page表示页面的根节点,Column/Row等元素为系统组件。针对不同的页面结构,ArkUI提供了不同的布局组件来帮助开发者实现对应布局的效果,例如Row用于实现线性布局。

布局元素的组成

布局相关的容器组件可形成对应的布局效果。例如,List组件可构成线性布局。

image-20241105232456511.png

**组件区域(蓝区方块):**组件区域表示组件的大小,width、height属性用于设置组件区域的大小。

**组件内容区(黄色方块):**组件内容区大小为组件区域大小减去组件的border值,组件内容区大小会作为组件内容(或者子组件)进行大小测算时的布局测算限制。

**组件内容(绿色方块):**组件内容本身占用的大小,比如文本内容占用的大小。组件内容和组件内容区不一定匹配,比如设置了固定的width和height,此时组件内容的大小就是设置的width和height减去padding和border值,但文本内容则是通过文本布局引擎测算后得到的大小,可能出现文本真实大小小于设置的组件内容区大小。当组件内容和组件内容区大小不一致时,align属性生效,定义组件内容在组件内容区的对齐方式,如居中对齐。

**组件布局边界(虚线部分):**组件通过margin属性设置外边距时,组件布局边界就是组件区域加上margin的大小。

如何选择布局

声明式UI提供了以下10种常见布局,开发者可根据实际应用场景选择合适的布局进行页面开发。

布局 应用场景
线性布局(Row、Column) 如果布局内子元素超过1个时,且能够以某种方式线性排列时优先考虑此布局。
层叠布局(Stack) 组件需要有堆叠效果时优先考虑此布局。层叠布局的堆叠效果不会占用或影响其他同容器内子组件的布局空间。例如Panel作为子组件弹出时将其他组件覆盖更为合理,则优先考虑在外层使用堆叠布局。
弹性布局(Flex) 弹性布局是与线性布局类似的布局方式。区别在于弹性布局默认能够使子组件压缩或拉伸。在子组件需要计算拉伸或压缩比例时优先使用此布局,可使得多个容器内子组件能有更好的视觉上的填充效果。
相对布局(RelativeContainer) 相对布局是在二维空间中的布局方式,不需要遵循线性布局的规则,布局方式更为自由。通过在子组件上设置锚点规则(AlignRules)使子组件能够将自己在横轴、纵轴中的位置与容器或容器内其他子组件的位置对齐。设置的锚点规则可以天然支持子元素压缩、拉伸、堆叠或形成多行效果。在页面元素分布复杂或通过线性布局会使容器嵌套层数过深时推荐使用。
栅格布局(GridRow、GridCol) 栅格是多设备场景下通用的辅助定位工具,可将空间分割为有规律的栅格。栅格不同于网格布局固定的空间划分,可以实现不同设备下不同的布局,空间划分更随心所欲,从而显著降低适配不同屏幕尺寸的设计及开发成本,使得整体设计和开发流程更有秩序和节奏感,同时也保证多设备上应用显示的协调性和一致性,提升用户体验。推荐内容相同但布局不同时使用。
媒体查询(@ohos.mediaquery) 媒体查询可根据不同设备类型或同设备不同状态修改应用的样式。例如根据设备和应用的不同属性信息设计不同的布局,以及屏幕发生动态改变时更新应用的页面布局。
列表(List) 使用列表可以高效地显示结构化、可滚动的信息。在ArkUI中,列表具有垂直和水平布局能力和自适应交叉轴方向上排列个数的布局能力,超出屏幕时可以滚动。列表适合用于呈现同类数据类型或数据类型集,例如图片和文本。
网格(Grid) 网格布局具有较强的页面均分能力、子元素占比控制能力。网格布局可以控制元素所占的网格数量、设置子元素横跨几行或者几列,当网格容器尺寸发生变化时,所有子元素以及间距等比例调整。推荐在需要按照固定比例或者均匀分配空间的布局场景下使用,例如计算器、相册、日历等。
轮播(Swiper) 轮播组件通常用于实现广告轮播、图片预览等。
选项卡(Tabs) 选项卡可以在一个页面内快速实现视图内容的切换,一方面提升查找信息的效率,另一方面精简用户单次获取到的信息量。

布局位置

position、offset等属性影响了布局容器相对于自身或其他组件的位置。

定位能力 使用场景 实现方式
绝对定位 对于不同尺寸的设备,使用绝对定位的适应性会比较差,在屏幕的适配上有缺陷。 使用【position】实现绝对定位,设置元素左上角相对于父容器左上角偏移位置。在布局容器中,设置该属性不影响父容器布局,仅在绘制时进行位置调整。
相对定位 相对定位不脱离文档流,即原位置依然保留,不影响元素本身的特性,仅相对于原位置进行偏移。 使用【offset】可以实现相对定位,设置元素相对于自身的偏移量。设置该属性,不影响父容器布局,仅在绘制时进行位置调整。

对子元素的约束

**拉伸:**容器组件尺寸发生变化时,增加或减小的空间全部分配给容器组件内指定区域。flexGrow和flexShrink属性:

  1. flexGrow基于父容器的剩余空间分配来控制组件拉伸。
  2. flexShrink设置父容器的压缩尺寸来控制组件压缩。

**缩放:**子组件的宽高按照预设的比例,随容器组件发生变化,且变化过程中子组件的宽高比不变。aspectRatio属性指定当前组件的宽高比来控制缩放,公式为:aspectRatio=width/height。

占比:子组件的宽高按照预设的比例,随祖先容器组件发生变化。

​ 基于通用属性的两种实现方式:

​ 1、子组件的宽高设置为百分比。

父组件与祖先组件宽高设置情况 子组件百分比
父组件设置宽或高 & 祖先组件未指定父组件宽或高 参考父组件的宽高
父组件设置宽或高 & 祖先组件指定父组件宽或高 参考祖先组件指定的父组件宽高
父组件未设置宽或高 & 祖先组件指定父组件宽或高 参考祖先组件指定的父组件宽高
父组件未设置宽或高 & 祖先组件未指定父组件宽或高 参考父组件的百分比参照。由于父组件未指定宽高,该百分比参照传递自祖先组件

​ 2、layoutWeight属性,使得子元素自适应占满剩余空间。

**隐藏:**隐藏能力是指容器组件内的子组件,按照其预设的显示优先级,随容器组件尺寸变化显示或隐藏,其中相同显示优先级的子组件同时显示或隐藏。

通过displayPriority属性来控制组件的显示和隐藏。

构建布局

我们主要掌握的有:线性布局、层叠布局、弹性布局、相对布局、栅格布局,那么接下来我们就理论与实操一起上,争取快速掌握。

注:【.justifyContent(FlexAlign.Center)】代表元素在垂直方向方向中心对齐,第一个元素与行首的距离与最后一个元素与行尾距离相同,为了更好做图片效果,后面很多示例都单独加了这个,可以自定义去掉这个代码块再看效果。

线性布局

线性布局(LinearLayout)是开发中最常用的布局,通过线性容器Row和Column构建。线性布局是其他布局的基础,其子元素在线性方向上(水平方向和垂直方向)依次排列。线性布局的排列方向由所选容器组件决定,Column容器内子元素按照垂直方向排列,Row容器内子元素按照水平方向排列。根据不同的排列方向,开发者可选择使用Row或Column容器创建线性布局。

Column

@Entry
@Component
struct TestPage {

  build() {
    Column(){
      Text("一帆風順").fontSize(15).width(65).height(50).backgroundColor(Color.Red)
      Text("二龍騰飛").fontSize(15).width(65).height(50).backgroundColor(Color.Gray)
      Text("三羊開泰").fontSize(15).width(65).height(50).backgroundColor(Color.Yellow)
      Text("四季平安").fontSize(15).width(65).height(50).backgroundColor(Color.Blue)
      Text("五福臨門").fontSize(15).width(65).height(50).backgroundColor(Color.White)
    }.backgroundColor("#66CCFF").width('100%').height('100%').justifyContent(FlexAlign.Center)
  }
}

image-20241106105230139.png

ROW

@Entry
@Component
struct TestPage {

  build() {
    Row(){
      Text("一帆風順").fontSize(15).width(65).height(50).backgroundColor(Color.Red)
      Text("二龍騰飛").fontSize(15).width(65).height(50).backgroundColor(Color.Gray)
      Text("三羊開泰").fontSize(15).width(65).height(50).backgroundColor(Color.Yellow)
      Text("四季平安").fontSize(15).width(65).height(50).backgroundColor(Color.Blue)
      Text("五福臨門").fontSize(15).width(65).height(50).backgroundColor(Color.White)
    }.backgroundColor("#66CCFF").width('100%').height('100%').justifyContent(FlexAlign.Center)
  }
}

image-20241106105321558.png

基本概念

  • 布局容器:具有布局能力的容器组件,可以承载其他元素作为其子元素,布局容器会对其子元素进行尺寸计算和布局排列。

  • 布局子元素:布局容器内部的元素。

  • 主轴:线性布局容器在布局方向上的轴线,子元素默认沿主轴排列。Row容器主轴为水平方向,Column容器主轴为垂直方向。

  • 交叉轴:垂直于主轴方向的轴线。Row容器交叉轴为垂直方向,Column容器交叉轴为水平方向。

  • 间距:布局子元素的间距。

布局子元素在排列方向上的间距

在布局容器内,可以通过【space】属性设置排列方向上子元素的间距,使各子元素在排列方向上有等间距效果。

@Entry
@Component
struct TestPage {

  build() {
    Row({ space: 7 }){
      Text("一帆風順").fontSize(15).width(65).height(50).backgroundColor(Color.Red)
      Text("二龍騰飛").fontSize(15).width(65).height(50).backgroundColor(Color.Gray)
      Text("三羊開泰").fontSize(15).width(65).height(50).backgroundColor(Color.Yellow)
      Text("四季平安").fontSize(15).width(65).height(50).backgroundColor(Color.Blue)
      Text("五福臨門").fontSize(15).width(65).height(50).backgroundColor(Color.White)
    }.backgroundColor("#66CCFF").width('100%').height('100%').justifyContent(FlexAlign.Center)
  }
}

image-20241106105544141.png

@Entry
@Component
struct TestPage {

  build() {
    Column({ space: 7 }){
      Text("一帆風順").fontSize(15).width(65).height(50).backgroundColor(Color.Red)
      Text("二龍騰飛").fontSize(15).width(65).height(50).backgroundColor(Color.Gray)
      Text("三羊開泰").fontSize(15).width(65).height(50).backgroundColor(Color.Yellow)
      Text("四季平安").fontSize(15).width(65).height(50).backgroundColor(Color.Blue)
      Text("五福臨門").fontSize(15).width(65).height(50).backgroundColor(Color.White)
    }.backgroundColor("#66CCFF").width('100%').height('100%').justifyContent(FlexAlign.Center)
  }
}

image-20241106105624812.png

容器内子元素在水平方向上的排列

这里分为Column于Row两个方向的排序。

Column用到的对象是HorizontalAlign,其属性有3:

HorizontalAlign.Start:子元素在水平方向左对齐。

HorizontalAlign.Center:默认为居中,子元素在水平方向居中对齐。

HorizontalAlign.End:子元素在水平方向右对齐。

Column示例

@Entry
@Component
struct TestPage {

  build() {
    Column({ space: 7 }){
      Text("一帆風順").fontSize(15).width(65).height(50).backgroundColor(Color.Red)
      Text("二龍騰飛").fontSize(15).width(65).height(50).backgroundColor(Color.Gray)
      Text("三羊開泰").fontSize(15).width(65).height(50).backgroundColor(Color.Yellow)
      Text("四季平安").fontSize(15).width(65).height(50).backgroundColor(Color.Blue)
      Text("五福臨門").fontSize(15).width(65).height(50).backgroundColor(Color.White)
    }.backgroundColor("#66CCFF").width('100%').height('100%').justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Start)
  }
}

image-20241106110134416.png

@Entry
@Component
struct TestPage {

  build() {
    Column({ space: 7 }){
      Text("一帆風順").fontSize(15).width(65).height(50).backgroundColor(Color.Red)
      Text("二龍騰飛").fontSize(15).width(65).height(50).backgroundColor(Color.Gray)
      Text("三羊開泰").fontSize(15).width(65).height(50).backgroundColor(Color.Yellow)
      Text("四季平安").fontSize(15).width(65).height(50).backgroundColor(Color.Blue)
      Text("五福臨門").fontSize(15).width(65).height(50).backgroundColor(Color.White)
    }.backgroundColor("#66CCFF").width('100%').height('100%').justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.End)
  }
}

image-20241106110250827.png

Row用到的对象是VerticalAlign,其属性有3:

VerticalAlign.Top:子元素在垂直方向顶部对齐。

VerticalAlign.Center:默认状态,子元素在垂直方向居中对齐。

VerticalAlign.Bottom:子元素在垂直方向底部对齐。

@Entry
@Component
struct TestPage {

  build() {
    Row({ space: 7 }){
      Text("一帆風順").fontSize(15).width(65).height(50).backgroundColor(Color.Red)
      Text("二龍騰飛").fontSize(15).width(65).height(50).backgroundColor(Color.Gray)
      Text("三羊開泰").fontSize(15).width(65).height(50).backgroundColor(Color.Yellow)
      Text("四季平安").fontSize(15).width(65).height(50).backgroundColor(Color.Blue)
      Text("五福臨門").fontSize(15).width(65).height(50).backgroundColor(Color.White)
    }.backgroundColor("#66CCFF").width('100%').height('100%').justifyContent(FlexAlign.Center)
    .alignItems(VerticalAlign.Top)
  }
}

image-20241106110550373.png

@Entry
@Component
struct TestPage {

  build() {
    Row({ space: 7 }){
      Text("一帆風順").fontSize(15).width(65).height(50).backgroundColor(Color.Red)
      Text("二龍騰飛").fontSize(15).width(65).height(50).backgroundColor(Color.Gray)
      Text("三羊開泰").fontSize(15).width(65).height(50).backgroundColor(Color.Yellow)
      Text("四季平安").fontSize(15).width(65).height(50).backgroundColor(Color.Blue)
      Text("五福臨門").fontSize(15).width(65).height(50).backgroundColor(Color.White)
    }.backgroundColor("#66CCFF").width('100%').height('100%').justifyContent(FlexAlign.Center)
    .alignItems(VerticalAlign.Bottom)
  }
}

image-20241106110628537.png

布局子元素在主轴上的排列方式:Column

在布局容器内,可以通过justifyContent属性设置子元素在容器主轴上的排列方式。可以从主轴起始位置开始排布,也可以从主轴结束位置开始排布,或者均匀分割主轴的空间。

justifyContent(FlexAlign.Start):元素在垂直方向方向首端对齐,第一个元素与行首对齐,同时后续的元素与前一个对齐。

justifyContent(FlexAlign.Center):元素在垂直方向方向中心对齐,第一个元素与行首的距离与最后一个元素与行尾距离相同。

justifyContent(FlexAlign.End):元素在垂直方向方向尾部对齐,最后一个元素与行尾对齐,其他元素与后一个对齐。

justifyContent(FlexAlign.SpaceBetween):垂直方向均匀分配元素,相邻元素之间距离相同。第一个元素与行首对齐,最后一个元素与行尾对齐。

justifyContent(FlexAlign.SpaceAround):垂直方向均匀分配元素,相邻元素之间距离相同。第一个元素到行首的距离和最后一个元素到行尾的距离是相邻元素之间距离的一半。

justifyContent(FlexAlign.SpaceEvenly):垂直方向均匀分配元素,相邻元素之间的距离、第一个元素与行首的间距、最后一个元素到行尾的间距都完全一样。

@Entry
@Component
struct TestPage {

  build() {
    Column({ space: 7 }){
      Text("一帆風順").fontSize(15).width(65).height(50).backgroundColor(Color.Red)
      Text("二龍騰飛").fontSize(15).width(65).height(50).backgroundColor(Color.Gray)
      Text("三羊開泰").fontSize(15).width(65).height(50).backgroundColor(Color.Yellow)
      Text("四季平安").fontSize(15).width(65).height(50).backgroundColor(Color.Blue)
      Text("五福臨門").fontSize(15).width(65).height(50).backgroundColor(Color.White)
    }.backgroundColor("#66CCFF").width('100%').height('100%').justifyContent(FlexAlign.Start)
  }
}

image-20241106111114019.png

@Entry
@Component
struct TestPage {

![image-20241106111114019.png](https://api.nutpi.net/file/topic/2024-11-27/image/53fac981b0b941b4a68d02780a38e66cb1695.png)

  build() {
    Column({ space: 7 }){
      Text("一帆風順").fontSize(15).width(65).height(50).backgroundColor(Color.Red)
      Text("二龍騰飛").fontSize(15).width(65).height(50).backgroundColor(Color.Gray)
      Text("三羊開泰").fontSize(15).width(65).height(50).backgroundColor(Color.Yellow)
      Text("四季平安").fontSize(15).width(65).height(50).backgroundColor(Color.Blue)
      Text("五福臨門").fontSize(15).width(65).height(50).backgroundColor(Color.White)
    }.backgroundColor("#66CCFF").width('100%').height('100%').justifyContent(FlexAlign.End)
  }
}

image-20241106111359074.png

@Entry
@Component
struct TestPage {

  build() {
    Column({ space: 7 }){
      Text("一帆風順").fontSize(15).width(65).height(50).backgroundColor(Color.Red)
      Text("二龍騰飛").fontSize(15).width(65).height(50).backgroundColor(Color.Gray)
      Text("三羊開泰").fontSize(15).width(65).height(50).backgroundColor(Color.Yellow)
      Text("四季平安").fontSize(15).width(65).height(50).backgroundColor(Color.Blue)
      Text("五福臨門").fontSize(15).width(65).height(50).backgroundColor(Color.White)
    }.backgroundColor("#66CCFF").width('100%').height('100%').justifyContent(FlexAlign.SpaceBetween)
  }
}

image-20241106111502416.png

@Entry
@Component
struct TestPage {

  build() {
    Column({ space: 7 }){
      Text("一帆風順").fontSize(15).width(65).height(50).backgroundColor(Color.Red)
      Text("二龍騰飛").fontSize(15).width(65).height(50).backgroundColor(Color.Gray)
      Text("三羊開泰").fontSize(15).width(65).height(50).backgroundColor(Color.Yellow)
      Text("四季平安").fontSize(15).width(65).height(50).backgroundColor(Color.Blue)
      Text("五福臨門").fontSize(15).width(65).height(50).backgroundColor(Color.White)
    }.backgroundColor("#66CCFF").width('100%').height('100%').justifyContent(FlexAlign.SpaceAround)
  }
}

image-20241106111610950.png

@Entry
@Component
struct TestPage {

  build() {
    Column({ space: 7 }){
      Text("一帆風順").fontSize(15).width(65).height(50).backgroundColor(Color.Red)
      Text("二龍騰飛").fontSize(15).width(65).height(50).backgroundColor(Color.Gray)
      Text("三羊開泰").fontSize(15).width(65).height(50).backgroundColor(Color.Yellow)
      Text("四季平安").fontSize(15).width(65).height(50).backgroundColor(Color.Blue)
      Text("五福臨門").fontSize(15).width(65).height(50).backgroundColor(Color.White)
    }.backgroundColor("#66CCFF").width('100%').height('100%').justifyContent(FlexAlign.SpaceEvenly)
  }
}

image-20241106111654691.png

布局子元素在主轴上的排列方式:Row

justifyContent(FlexAlign.Start):元素在水平方向首端对齐,第一个元素与行首对齐,同时后续的元素与前一个对齐。

justifyContent(FlexAlign.Center):元素在水平方向中心对齐,第一个元素与行首的距离与最后一个元素与行尾距离相同。

justifyContent(FlexAlign.End):元素在水平方向尾部对齐,最后一个元素与行尾对齐,其他元素与后一个对齐。

justifyContent(FlexAlign.SpaceBetween):水平方向均匀分配元素,相邻元素之间距离相同。第一个元素与行首对齐,最后一个元素与行尾对齐。

justifyContent(FlexAlign.SpaceAround):水平方向均匀分配元素,相邻元素之间距离相同。第一个元素到行首的距离和最后一个元素到行尾的距离是相邻元素之间距离的一半。

justifyContent(FlexAlign.SpaceEvenly):水平方向均匀分配元素,相邻元素之间的距离、第一个元素与行首的间距、最后一个元素到行尾的间距都完全一样。

@Entry
@Component
struct TestPage {

  build() {
    Row({ space: 7 }){
      Text("一帆風順").fontSize(15).width(65).height(50).backgroundColor(Color.Red)
      Text("二龍騰飛").fontSize(15).width(65).height(50).backgroundColor(Color.Gray)
      Text("三羊開泰").fontSize(15).width(65).height(50).backgroundColor(Color.Yellow)
    }.backgroundColor("#66CCFF").width('100%').height('100%').justifyContent(FlexAlign.Start)
  }
}

image-20241106112021831.png

image-20241106112114845.png

image-20241106112143467.png

image-20241106112212629.png

image-20241106112237417.png

自适应拉伸

在线性布局下,常用空白填充组件Blank,在容器主轴方向自动填充空白空间,达到自适应拉伸效果。Row和Column作为容器,只需要添加宽高为百分比,当屏幕宽高发生变化时,会产生自适应效果。

image-20241106113752541.png

自适应缩放

自适应缩放是指子元素随容器尺寸的变化而按照预设的比例自动调整尺寸,适应各种不同大小的设备。在线性布局中,可以使用以下两种方法实现自适应缩放。

父容器尺寸确定时,使用layoutWeight属性设置子元素和兄弟元素在主轴上的权重,忽略元素本身尺寸设置,使它们在任意尺寸的设备下自适应占满剩余空间。

@Entry
@Component
struct TestPage {
  build() {
    Column({ space: 50 }) {
      Row() {
        Column() {
          Text('一帆風順')
            .textAlign(TextAlign.Center)
        }.layoutWeight(1).backgroundColor(Color.Red).height('100%')

        Column() {
          Text('二龍騰飛')
            .textAlign(TextAlign.Center)
        }.layoutWeight(2).backgroundColor(Color.Gray).height('100%')

        Column() {
          Text('三羊開泰')
            .textAlign(TextAlign.Center)
        }.layoutWeight(3).backgroundColor(Color.Yellow).height('100%')
      }.height('20%')

      Row() {
        Column() {
          Text('一帆風順')
            .textAlign(TextAlign.Center)
        }.layoutWeight(2).backgroundColor(Color.Red).height('100%')

        Column() {
          Text('二龍騰飛')
            .textAlign(TextAlign.Center)
        }.layoutWeight(5).backgroundColor(Color.Gray).height('100%')

        Column() {
          Text('三羊開泰')
            .textAlign(TextAlign.Center)
        }.layoutWeight(3).backgroundColor(Color.Yellow).height('100%')
      }.height('20%')

      Row() {
        Column() {
          Text('一帆風順')
            .textAlign(TextAlign.Center)
        }.layoutWeight(50).backgroundColor(Color.Red).height('100%')

        Column() {
          Text('二龍騰飛')
            .textAlign(TextAlign.Center)
        }.layoutWeight(40).backgroundColor(Color.Gray).height('100%')

        Column() {
          Text('三羊開泰')
            .textAlign(TextAlign.Center)
        }.layoutWeight(10).backgroundColor(Color.Yellow).height('100%')
      }.height('20%')

      Row() {
        Column() {
          Text('一帆風順')
            .textAlign(TextAlign.Center)
        }.layoutWeight(33).backgroundColor(Color.Red).height('100%')

        Column() {
          Text('二龍騰飛')
            .textAlign(TextAlign.Center)
        }.layoutWeight(33).backgroundColor(Color.Gray).height('100%')

        Column() {
          Text('三羊開泰')
            .textAlign(TextAlign.Center)
        }.layoutWeight(33).backgroundColor(Color.Yellow).height('100%')
      }.height('20%')
    }.backgroundColor("#66CCFF").width('100%').height('100%')
  }
}

image-20241106114426501.png

自适应延伸

自适应延伸是指在不同尺寸设备下,当页面的内容超出屏幕大小而无法完全显示时,可以通过滚动条进行拖动展示。这种方法适用于线性布局中内容无法一屏展示的场景。通常有以下两种实现方式。

在List中添加滚动条:当List子项过多一屏放不下时,可以将每一项子元素放置在不同的组件中,通过滚动条进行拖动展示。可以通过scrollBar属性设置滚动条的常驻状态,edgeEffect属性设置拖动到内容最末端的回弹效果。

使用Scroll组件:在线性布局中,开发者可以进行垂直方向或者水平方向的布局。当一屏无法完全显示时,可以在Column或Row组件的外层包裹一个可滚动的容器组件Scroll来实现可滑动的线性布局。

垂直方向布局中使用Scroll组件:

@Entry
@Component
struct TestPage {
  scroller: Scroller = new Scroller();
  private arr: string[] =
    ["一帆风顺", "二龙腾飞", "三阳开泰", "四季平安", "五福临门", "六六大顺", "七星高照", "八方来财"];

  build() {
    Scroll(this.scroller) {
      Column() {
        ForEach(this.arr, (item: string) => {
          Text(item)
            .width('90%')
            .height(150)
            .backgroundColor(Color.White)
            .borderRadius(15)// 圆角
            .fontSize(27)// 字体
            .textAlign(TextAlign.Center)// 文本居中
            .margin({ top: 10 })// 外边距上10px
            .padding({ bottom: 50 }) // 内边距下50px

        })
      }.width('100%')
    }
    .backgroundColor('#66CCFF')
    .scrollable(ScrollDirection.Vertical) // 滚动方向为垂直方向
    .scrollBar(BarState.On) // 滚动条常驻显示
    .scrollBarColor(Color.Gray) // 滚动条颜色
    .scrollBarWidth(10) // 滚动条宽度
    .edgeEffect(EdgeEffect.Spring) // 滚动到边沿后回弹
  }
}

image-20241106115422789.png

@Entry
@Component
struct TestPage {
  scroller: Scroller = new Scroller();
  private arr: string[] =
    ["一帆风顺", "二龙腾飞", "三阳开泰", "四季平安", "五福临门", "六六大顺", "七星高照", "八方来财"];

  build() {
    Scroll(this.scroller) {
      Row() {
        ForEach(this.arr, (item: string) => {
          Text(item)
            .width('30%')
            .height(220)
            .backgroundColor(Color.White)
            .borderRadius(15)// 圆角
            .fontSize(27)// 字体
            .textAlign(TextAlign.Center)// 文本居中
            .margin({ left: 10 })// 外边距左10px

            Blank() // 自适应
        })
      }.height('100%')
    }
    .backgroundColor("#66CCFF")
    .scrollable(ScrollDirection.Horizontal) // 滚动方向为水平方向
    .scrollBar(BarState.On) // 滚动条常驻显示
    .scrollBarColor(Color.Gray) // 滚动条颜色
    .scrollBarWidth(20) // 滚动条宽度
    .edgeEffect(EdgeEffect.Spring) // 滚动到边沿后回弹
  }
}

image-20241106120115822.png

image-20241106120158334.png

总结

使用线性布局可以完成我们平时的简单布局,使用自适应等操作可以适当的当我们的设计更加的标准,免去了计算像素的问题,并且在不同机型上也有不错的兼容性表现,大大的节约了我们适配的时间,线性布局只是基础布局后面我们还会学习其它布局,例如:栅格布局就是一个非常不错的布局方式,可以巧妙的完成各类难度的布局任务,我们下一章节就开始栅格布局的讲解。

收藏00

登录 后评论。没有帐号? 注册 一个。