【纯血鸿蒙】——自适应布局如何实现?

news2024/11/28 18:51:32

界面级一多能力有 2 类:

  1. 自适应布局: 略微调整界面结构

  2. 响应式布局:比较大的界面调整

img

img

img

  • 本文章先主要讲解自适应布局,响应式布局再后面文章再细讲。话不多说,开始了。

自适应布局

针对常见的开发场景,方舟开发框架提炼了七种自适应布局能力,这些布局可以独立使用,也可多种布局叠加使用。

自适应布局类别自适应布局能力使用场景实现方式
自适应拉伸拉伸能力容器组件尺寸发生变化时,增加或减小的空间全部分配给容器组件内指定区域Flex布局的flexGrow和flexShrink属性
均分能力容器组件尺寸发生变化时,增加或减小的空间均匀分配给容器组件内所有空白区域Row组件、Column组件或Flex组件的justifyContent属性设置为FlexAlign.SpaceEvenly
自适应缩放占比能力子组件的宽或高按照预设的比例,随容器组件发生变化。基于通用属性的两种实现方式: - 将子组件的宽高设置为父组件宽高的百分比 - layoutWeight属性
缩放能力子组件的宽高按照预设的比例,随容器组件发生变化,且变化过程中子组件的宽高比不变布局约束的aspectRatio属性
自适应延伸延伸能力容器组件内的子组件,按照其在列表中的先后顺序,随容器组件尺寸变化显示或隐藏。基于容器组件的两种实现方式: - 通过List组件实现 - 通过Scroll组件配合Row组件或Column组件实现
隐藏能力容器组件内的子组件,按照其预设的显示优先级,随容器组件尺寸变化显示或隐藏。相同显示优先级的子组件同时显示或隐藏布局约束的displayPriority属性
自适应折行折行能力容器组件尺寸发生变化时,如果布局方向尺寸不足以显示完整内容,自动换行Flex组件的wrap属性设置为FlexWrap.Wrap

下面我们依次介绍这几种自适应布局能力。

1. 拉伸能力

拉伸能力是指容器组件尺寸发生变化时,增加或减小的空间全部分配给容器组件内指定区域。

拉伸能力通常通过Flex布局中的flexGrow和flexShrink属性实现,flexGrow和flexShink属性常与flexBasis属性搭配使用,故将这三个属性放在一起介绍。

属性类型默认值描述
flexGrownumber0仅当父容器宽度大于所有子组件宽度的总和时,该属性生效。配置了此属性的子组件,按照比例拉伸,分配父容器的多余空间。
flexShrinknumber1仅当父容器宽度小于所有子组件宽度的总和时,该属性生效。配置了此属性的子组件,按照比例收缩,分配父容器的不足空间。
flexBasisauto | Lengthauto设置组件在Flex容器中主轴方向上基准尺寸。'auto’意味着使用组件原始的尺寸,不做修改。 flexBasis属性不是必须的,通过width或height也可以达到同样的效果。当flexBasis属性与width或height发生冲突时,以flexBasis属性为准。

说明:

  • 开发者期望将父容器的剩余空间全部分配给某空白区域时,也可以通过Blank组件实现。注意仅当父组件为Row\Column\Flex组件时,Blank组件才会生效。

  • 类Web开发范式也是通过flex-grow和flex-shrink实现拉伸能力,同时也支持配置flex-basis,详见通用样式。

  • 类Web开发范式没有提供blank组件,但可以通过div组件模拟blank组件的行为,如“<div style=‘flex-grow: 1; flex-shrink: 0; flex-basis: 0’></div>”。

示例1

本示例中的页面由中间的内容区(包含一张图片)以及两侧的留白区组成,各区域的属性配置如下。

  • 中间内容区的宽度设置为400vp,同时将flexGrow属性设置为1,flexShrink属性设置为0。

  • 两侧留白区的宽度设置为150vp,同时将flexGrow属性设置为0,flexShrink属性设置为1。

由上可知,父容器的基准尺寸是700vp(150vp+400vp+150vp)。

可以通过拖动底部的滑动条改变父容器的尺寸,查看布局变化。

  • 当父容器的尺寸大于700vp时,父容器中多余的空间全部分配给中间内容区。

  • 当父容器的尺寸小于700vp时,左右两侧的留白区按照“1:1”的比例收缩(即平均分配父容器的不足空间)。

@Entry
@Component
struct FlexibleCapabilitySample1 {
  @State containerWidth: number = 402
​
  // 底部滑块,可以通过拖拽滑块改变容器尺寸。
  @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属性,将多余的空间全部分配给图片,将不足的控件全部分配给两侧空白区域。
          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)
  }
}

示例2

文字和开关的尺寸固定,仅有中间空白区域(Blank组件)随父容器尺寸变化而伸缩。

@Entry
@Component
struct FlexibleCapabilitySample2 {
  @State rate: number = 0.8
​
  // 底部滑块,可以通过拖拽滑块改变容器尺寸
  @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组件实现拉伸能力
          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)
  }
}

2. 均分能力

均分能力是指容器组件尺寸发生变化时,增加或减小的空间均匀分配给容器组件内所有空白区域。它常用于内容数量固定、均分显示的场景,比如工具栏、底部菜单栏等。

均分能力可以通过将Row组件、Column组件或Flex组件的justifyContent属性设置为FlexAlign.SpaceEvenly实现,即子元素在父容器主轴方向等间距布局,相邻元素之间的间距、第一个元素与行首的间距、最后一个元素到行尾的间距都完全一样。

说明:

  • 均分能力还可以通过其它方式实现,如使用Grid网格组件或在每个组件间添加Blank组件等。

  • 类Web开发范式中,通过将div组件的justify-content属性设置为space-evenly来实现均分布局。

示例:

父容器尺寸变化过程中,图标及文字的尺寸不变,图标间的间距及图标离左右边缘的距离同时均等改变。


@Entry
@Component
struct EquipartitionCapabilitySample {
  readonly list: number [] = [0, 1, 2, 3]
  @State rate: number = 0.6
​
  // 底部滑块,可以通过拖拽滑块改变容器尺寸
  @Builder slider() {
    Slider({ value: this.rate * 100, min: 30, max: 60, style: SliderStyle.OutSet })
      .blockColor(Color.White)
      .width('60%')
      .onChange((value: number) => {
        this.rate = value / 100
      })
      .position({ x: '20%', y: '80%' })
  }
​
  build() {
    Column() {
      Column() {
        // 均匀分配父容器主轴方向的剩余空间
        Row() {
          ForEach(this.list, (item:number) => {
            Column() {
              Image($r("app.media.icon")).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)
            .flexShrink(1)
          })
        }
        .width('100%')
        .justifyContent(FlexAlign.SpaceEvenly)
        // 均匀分配父容器主轴方向的剩余空间
        Row() {
          ForEach(this.list, (item:number) => {
            Column() {
              Image($r("app.media.icon")).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)
            .flexShrink(1)
          })
        }
        .width('100%')
        .justifyContent(FlexAlign.SpaceEvenly)
      }
      .width(this.rate * 100 + '%')
      .height(222)
      .padding({ top: 16 })
      .backgroundColor('#FFFFFF')
      .borderRadius(16)
​
      this.slider()
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F1F3F5')
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center)
  }
}

3. 占比能力

占比能力是指子组件的宽高按照预设的比例,随父容器组件发生变化。

占比能力通常有两种实现方式:

  • 将子组件的宽高设置为父组件宽高的百分比。

  • 通过layoutWeight属性配置互为兄弟关系的组件在父容器主轴方向的布局权重。

    • 当父容器尺寸确定时,其子组件按照开发者配置的权重比例分配父容器中主轴方向的空间。

    • 仅当父容器是Row、Column或者Flex时,layoutWeight属性才会生效。

    • 设置layoutWeight属性后,组件本身的尺寸会失效。比如同时设置了.width(‘40%’)和.layoutWeight(1),那么只有.layoutWeight(1)会生效。

layoutWeight存在使用限制,所以实际使用过程中大多通过将子组件宽高设置为父组件的百分比来实现占比能力。

说明:

  • 占比能力在实际开发中使用的非常广泛,可以通过很多不同的方式实现占比能力,如还可以通过Grid组件的columnsTemplate属性设置网格容器中列的数量及其宽度比例,或通过配置子组件在栅格(本章后文将详细介绍栅格系统)中占据不同的列数来实现占比能力。

  • 类Web开发范式同样支持以百分比的形式设置组件的宽高。

  • 与声明式开发范式中的layoutWeight属性类似,类Web开发范式提供了flex-weight样式用于配置互为兄弟关系的组件在父容器主轴方向的布局权重。

示例:

简单的播放控制栏,其中“上一首”、“播放/暂停”、“下一首”的layoutWeight属性都设置为1,因此它们按照“1:1:1”的比例均分父容器主轴方向的空间。

将三个按钮的.layoutWeight(1)分别替换为.width(‘33%’)、.width(‘34%’)、.width(‘33%’),也可以实现与当前同样的显示效果。

@Entry
@Component
struct ProportionCapabilitySample {
  @State rate: number = 0.5
​
  // 底部滑块,可以通过拖拽滑块改变容器尺寸
  @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)  // 设置子组件在父容器主轴方向的布局权重
          .justifyContent(FlexAlign.Center)
          .alignItems(HorizontalAlign.Center)
​
          Column() {
            Image($r("app.media.pause"))
              .width(48)
              .height(48)
          }
          .height(96)
          .layoutWeight(1)  // 设置子组件在父容器主轴方向的布局权重
          .backgroundColor('#66F1CCB8')
          .justifyContent(FlexAlign.Center)
          .alignItems(HorizontalAlign.Center)
​
          Column() {
            Image($r("app.media.next"))
              .width(48)
              .height(48)
          }
          .height(96)
          .layoutWeight(1)  // 设置子组件在父容器主轴方向的布局权重
          .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)
  }
}

4. 缩放能力

缩放能力是指子组件的宽高按照预设的比例,随容器组件发生变化,且变化过程中子组件的宽高比不变。

缩放能力通过使用百分比布局配合固定宽高比(aspectRatio属性)实现当容器尺寸发生变化时,内容自适应调整。

说明: 类Web开发范式同样提供了aspect-ratio样式固定比例,用于固定组件的宽高比。

示例:

为方便查看效果,示例中特意给Column组件加了边框。可以看到Column组件随着其Flex父组件尺寸变化而缩放的过程中,始终保持预设的宽高比,其中的图片也始终正常显示。

@Entry
@Component
struct ScaleCapabilitySample {
  @State sliderWidth: number = 400
  @State sliderHeight: number = 400
​
  // 底部滑块,可以通过拖拽滑块改变容器尺寸
  @Builder slider() {
    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: '80%' })
    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: '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)
  }
}

5. 延伸能力

延伸能力是指容器组件内的子组件,按照其在列表中的先后顺序,随容器组件尺寸变化显示或隐藏。它可以根据显示区域的尺寸,显示不同数量的元素。

延伸能力通常使用带有滚动功能的组件来实现:

  • 通过List组件实现。

  • 通过Scroll组件配合Row组件或Column组件实现。

  • 通过Grid组件,只设置行或只设置列也可以实现滚动,也能实现延伸。

说明:

  • List、Row或Column组件中子节点的在页面显示时就已经全部完成了布局计算及渲染,只不过受限于父容器尺寸,用户只能看到一部分。随着父容器尺寸增大,用户可以看到的子节点数目也相应的增加。用户还可以通过手指滑动触发列表滑动,查看被隐藏的子节点。

  • 类Web开发范式同样可以使用list组件实现延伸能力。

  • 类Web开发范式没有提供scroll组件,但可以将div组件的overflow样式设置为scroll(即div组件主轴方向上子元素的尺寸超过div组件本身的尺寸时进行滚动显示)来模拟scroll组件的行为。

示例:

当父容器的尺寸发生改变时,页面中显示的图标数量随之发生改变。

分别通过List组件实现及通过Scroll组件配合Row组件实现。

(1)通过List组件实现。

@Entry
@Component
struct ExtensionCapabilitySample1 {
  @State rate: number = 0.60
  readonly appList: number [] = [0, 1, 2, 3, 4, 5, 6, 7]
​
  // 底部滑块,可以通过拖拽滑块改变容器尺寸
  @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组件实现隐藏能力
        List({ space: 10 }) {
          ForEach(this.appList, (item:number) => {
            ListItem() {
              Column() {
                Image($r("app.media.icon")).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)
  }
}

(2)通过Scroll组件配合Row组件实现。

@Entry
@Component
struct ExtensionCapabilitySample2 {
  private scroller: Scroller = new Scroller()
  @State rate: number = 0.60
  @State appList: number [] = [0, 1, 2, 3, 4, 5, 6, 7]
​
  // 底部滑块,可以通过拖拽滑块改变容器尺寸
  @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() {
      // 通过Scroll和Row组件实现隐藏能力
      Scroll(this.scroller) {
        Row({ space: 10 }) {
          ForEach(this.appList, () => {
            Column() {
              Image($r("app.media.icon")).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)
          })
        }
        .padding({ top: 16, left: 10 })
        .height(118)
        .borderRadius(16)
        .backgroundColor(Color.White)
      }
      .scrollable(ScrollDirection.Horizontal)
      .width(this.rate * 100 + '%')
​
      this.slider()
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F1F3F5')
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center)
  }
}

6. 隐藏能力

隐藏能力是指容器组件内的子组件,按照其预设的显示优先级,随容器组件尺寸变化显示或隐藏,其中相同显示优先级的子组件同时显示或隐藏。它是一种比较高级的布局方式,常用于分辨率变化较大,且不同分辨率下显示内容有所差异的场景。主要思想是通过增加或减少显示内容,来保持最佳的显示效果。

隐藏能力通过设置布局优先级(displayPriority属性)来控制显隐,当布局主轴方向剩余尺寸不足以满足全部元素时,按照布局优先级大小,从小到大依次隐藏,直到容器能够完整显示剩余元素。具有相同布局优先级的元素将同时显示或者隐藏。

说明: 类Web开发范式同样支持display-index样式,用于设置布局优先级。

示例:

父容器尺寸发生变化时,其子元素按照预设的优先级显示或隐藏。

@Entry
@Component
struct HiddenCapabilitySample {
  @State rate: number = 0.45
​
  // 底部滑块,可以通过拖拽滑块改变容器尺寸
  @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)  // 布局优先级
​
          Image($r("app.media.down"))
            .width(48)
            .height(48)
            .objectFit(ImageFit.Contain)
            .margin({ left: 12, right: 12 })
            .displayPriority(2)  // 布局优先级
​
          Image($r("app.media.pause"))
            .width(48)
            .height(48)
            .objectFit(ImageFit.Contain)
            .margin({ left: 12, right: 12 })
            .displayPriority(3)  // 布局优先级
​
          Image($r("app.media.next"))
            .width(48)
            .height(48)
            .objectFit(ImageFit.Contain)
            .margin({ left: 12, right: 12 })
            .displayPriority(2)  // 布局优先级
​
          Image($r("app.media.list"))
            .width(48)
            .height(48)
            .objectFit(ImageFit.Contain)
            .margin({ left: 12, right: 12 })
            .displayPriority(1)  // 布局优先级
        }
        .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)
  }
}

7. 折行能力

折行能力是指容器组件尺寸发生变化,当布局方向尺寸不足以显示完整内容时自动换行。它常用于横竖屏适配或默认设备向平板切换的场景。

折行能力通过使用 Flex折行布局 (将wrap属性设置为FlexWrap.Wrap)实现,当横向布局尺寸不足以完整显示内容元素时,通过折行的方式,将元素显示在下方。

说明: 类Web开发范式通过将div组件的flex-warp样式设置为wrap来使用折行能力。

示例:

父容器中的图片尺寸固定,当父容器尺寸发生变化,其中的内容做自适应换行。

 

@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')
  ]

  // 底部滑块,可以通过拖拽滑块改变容器尺寸
  @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参数实现自适应折行
        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')
  }
}

以上就是自适应布局的全部技巧,熟练掌握便可以应付大多数自适应布局场景了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1802442.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VS(visual studio)搭建QT开发环境插件安装

优先安装QT Qt6 官网QtCreator 下载与安装方法win10_qt6下载-CSDN博客 如果安装vs2019,打开installer,安装c环境 选择c 下载vsix后&#xff0c;双击安装即可。 插件下载&#xff1a; Index of /qtproject/official_releases/vsaddin/ 创建QT项目&#xff1a; 创建完成&…

力扣560. 和为 K 的子数组

Problem: 560. 和为 K 的子数组 文章目录 题目描述思路复杂度Code 题目描述 思路 1.初始化一个哈希表preSum&#xff0c;用于记录前缀和及其出现次数,ans记录和为k的子数组数量、sum_i记录当前前缀和&#xff1b; 2.将前缀和为 0 的情况存入哈希表&#xff0c;表示前缀和为 0 出…

Spring boot项目

一. Spring boot 安装地址 https://start.spring.io/ 二. 选择 三. idea配置 找到下载的文件解压缩&#xff0c;打开pom.xml(选择从idea打开)

Django与MySQL:配置数据库的详细步骤

文章目录 Django-MySQL 配置配置完执行数据迁移&#xff0c;如果报错: Error loading MySQLdb module&#xff0c; Django-MySQL 配置 # settings.pyDATABASES {# 默认配置sqlite3数据库# default: {# ENGINE: django.db.backends.sqlite3,# NAME: BASE_DIR / db.sqli…

初识BootLoader(二)

BootLoader的功能 BootLoader&#xff0c;通常是驻留在ECU非易失性存储器&#xff08;NVM&#xff0c;None Valitale Momory&#xff09;中的一段程序加载代码&#xff0c;每次ECU复位后&#xff0c;都会运行bootloader。它会检查是否有来自通信总线的远程程序加载请求&#x…

一个 buffer 使用的负反馈实例

端到端拥塞控制其实就是负反馈的实施。典型的做法是识别到一系列标志性事件&#xff0c;比如丢包&#xff0c;时延增加等&#xff0c;然后对这些事件做反应&#xff0c;进而形成负反馈&#xff0c;但 inflight 守恒是一种完全不同的做法&#xff0c;它将负反馈平铺到了整个传输…

所谓自律,就是去对抗那些廉价的快乐

所谓自律&#xff0c;就是去对抗那些廉价的快乐 以下文章来源于洞见 &#xff0c;作者洞见 导语 打败内心那只及时享乐的猴子。 董宇辉说过这样一句话&#xff1a;“廉价的快乐是直接给你想要的东西&#xff0c;高等的快乐则会给你设置重重阻碍。” 廉价的快乐&#xff0c;就…

什么情况下需要配戴助听器

以下几种情况需要考虑配戴助听器&#xff1a; 1、听力无波动3个月以上的感音神经性听力障碍。如:先天性听力障碍、老年性听力障碍、噪声性听力障碍、突聋的稳定期等&#xff0c;均可选配合适的助听器。 2、年龄方面。使用助听器没有严格的年龄限制&#xff0c;从出生数周的婴…

【Ardiuno】ESP32单片机初试点亮LED小灯

之前用的Ardiuno的主板做过一些简单的开发实验&#xff0c;按照相关说明还是很容易进行操作的。最近看了ESP32可以有wifi的功能&#xff0c;也就买来实验一下。 ESP32的主板开发环境安装&#xff0c;按照说明的安装下载程序总是报错&#xff0c;又上网搜索半天最后按照CSDN上某…

LeetCode刷题之HOT100之颜色分类

下午好呀&#xff0c;大家&#xff01;昨天估计是喝了假酒&#xff0c;现在没有胃口&#xff0c;喝酒真的没有任何好处。以后尽量避免此活动。今天几乎没睡觉&#xff0c;准备做完这题回宿舍&#xff0c;把电脑也带回去。 1、题目描述 2、逻辑分析 对颜色排序&#xff0c;要求…

SpeedyBee飞塔F405 V3 50A

遥控器常用的几种协议&#xff1a; 一文打尽PWM协议、PPM协议、PCM协议、SBUS协议、XBUS协议、DSM协议 | STM32的通用定时器TIM3实现PPM信号输出 - 蔡子CaiZi - 博客园 (cnblogs.com) SpeedyBee飞塔的官方教程&#xff1a; FlowUs 息流 - 新一代生产力工具 为8位电调刷写固…

【小白专用】C# Task 类异步操作-浅谈

注解 Task类表示不返回值并且通常以异步方式执行的单个操作。 Task 对象是在 .NET Framework 4 中首次引入的 基于任务的异步模式 的中心组件之一。 由于对象执行的工作 Task 通常在线程池线程上异步执行&#xff0c;而不是在主应用程序线程上同步执行&#xff0c;因此可以使用…

双网卡配置IP和路由总结

1.在网络适配器属性IPv4中设置默认网关&#xff08;记网关地址为A&#xff09;&#xff0c;将会在本地路由表中新增一条记录&#xff1a; 网络号子网掩码网关地址0.0.0.00.0.0.0A 2.如果有两个网卡&#xff08;假设一个连接内网&#xff0c;一个连接互联网&#xff09;&#…

【C语言】冒泡排序(经典算法,干货满满!!!)

目录 前言1、原理2、冒泡排序的应用3、对冒泡排序的应用的优化4、冒泡排序适用于以下情况 前言 冒泡排序&#xff08;Bubble Sort&#xff09;是一种简单直观的排序算法&#xff0c;它重复地遍历要排序的数列&#xff0c;一次比较两个元素&#xff0c;如果它们的顺序错误就把它…

扩散模型条件生成——Classifier Guidance和Classifier-free Guidance原理解析

1、前言 从讲扩散模型到现在。我们很少讲过条件生成&#xff08;Stable DIffusion曾提到过一点&#xff09;&#xff0c;所以本篇内容。我们就来具体讲一下条件生成。这一部分的内容我就不给原论文了&#xff0c;因为那些论文并不只讲了条件生成&#xff0c;还有一些调参什么的…

【ARFoundation自学04】AR Tracked Image 图像追踪识别

图像识别是很常用的AR功能&#xff01;AR foundation 可以帮助我们轻松实现&#xff01; 1.安装插件 首先还是在资源包中导入ARfoundation 。然后搭建基本的AR ARFoundation框架&#xff01; 2.创建AR session 和XR origin结构&#xff01; 3.然后在XR Origin 物体身上添加A…

ubuntu22.04编译OpenCV4.9(带contrib-4.9.0)

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;4.9.0 opencv_contrib版本&#xff1a;4.9.0 源码下载 OPenCV4.9.0下载地址&#xff1a;https://github.com/opencv/opencv/releases/tag/4.9.0 如下图所示&#xff1a; 按箭头所指点击下载source code(tar.gz)文件到…

电机专用32位MCU PY32MD310,Arm® Cortex-M0+内核

PY32MD310是一颗专为电机控制设计的MCU&#xff0c;非常适合用做三相/单相 BLDC/PMSM 的主控芯片。芯片采用了高性能的 32 位 ARM Cortex-M0 内核&#xff0c;QFN32封装。内置最大 64 Kbytes flash 和 8 Kbytes SRAM 存储器&#xff0c;最高48 MHz工作频率&#xff0c;多达 16 …

Day51 动态规划part10+Day52 动态规划part11

LC121买卖股票的最佳时机&#xff08;未掌握&#xff09; 暴力&#xff1a;双层循环寻找最优间距&#xff0c;每一次都确定一个起点&#xff0c;遍历剩余节点当作终点 贪心&#xff1a;取最左最小值&#xff0c;不断遍历那么得到的差值最最大值就是最大利润。 动态规划 dp数组…