HarmonyOS鸿蒙Next中怎么根据组件宽度适应横排或竖排

HarmonyOS鸿蒙Next中怎么根据组件宽度适应横排或竖排 怎么实现,2块组件,如果能在同一行放置,则横排;如果超出屏幕,则竖排

cke_295.png


更多关于HarmonyOS鸿蒙Next中怎么根据组件宽度适应横排或竖排的实战教程也可以访问 https://www.itying.com/category-93-b0.html

8 回复

结合Flex布局的wrap属性与栅格系统实现自动换行:

@Entry
@Component
struct AutoWrapLayout {
  build() {
    Flex({ direction: FlexDirection.Row, wrap: FlexWrap.Wrap }) {
      Component1()
        .flexShrink(0) // 禁止收缩
        .margin(10)
      Component2()
        .flexShrink(0)
        .margin(10)
    }
    .width('100%')
    .justifyContent(FlexAlign.Start)
  }
}

当横向空间不足时自动折行

需通过flexShrink(0)禁止组件收缩

配合margin保持间距一致性

更多关于HarmonyOS鸿蒙Next中怎么根据组件宽度适应横排或竖排的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


看到很多回答都是 Flex 容器的 wrap,这个是换行,并没有实现竖排,如果有第三个组件,就会不合适,需要改的地方应该是布局方向,如flex的direction。但是这就会产生一个新的问题,如何判断子组件超出了父组件,目前没有直接的api可以判断,可以通过onSizeChange记录并计算

import { BusinessError } from "@kit.BasicServicesKit";
import { hilog } from "@kit.PerformanceAnalysisKit";
import { OpenLinkOptions } from "@kit.AbilityKit";

@Entry
@Component
struct Index {
  @State direction1: FlexDirection = FlexDirection.Row;
  @State maxWidth: Length = 250;
  //父容器宽度 初始化为auto
  @State boxWidth: Length |undefined = 'auto';
  build() {
    Flex({
      direction:this.direction1,
    }){
      Column(){

      }
      .width(100)
      .backgroundColor(Color.Yellow)
      .aspectRatio(1)
      Column(){

      }
      .width(100)
      .backgroundColor(Color.Red)
      .aspectRatio(1)
      Column(){

      }
      .width(100)
      .backgroundColor(Color.Blue)
      .aspectRatio(1)
    }
    .width(this.boxWidth)
    .onSizeChange((oldValue: SizeOptions, newValue: SizeOptions)=>{
      if(oldValue.width === 0){
        if (Number(newValue.width) > this.maxWidth) {
          this.direction1 = FlexDirection.Column;
        }
      }
      console.log("xxx oldValue",oldValue.width, oldValue.height)
      console.log("xxx newValue",newValue.width, newValue.height)
    })
  }
}

HarmonyOS的流畅动画和过渡效果让操作更加顺畅,体验极佳。

方案一:使用 GridRow 栅格布局(推荐)

原理: GridRow 是响应式栅格容器,其子组件 GridCol 可根据断点自动调整布局。当一行空间不足时,GridCol 会自动换行,实现横排转竖排的效果。

示例代码

@Entry
@Component
struct AdaptiveLayoutExample {
  build() {
    GridRow() {
      // 第一块组件
      GridCol({ span: { xs: 12, sm: 6 } }) { // 小屏占满12列(整行),中屏占6列(半行)
        Text('组件A')
          .height(100)
          .backgroundColor(Color.Blue)
      }

      // 第二块组件
      GridCol({ span: { xs: 12, sm: 6 } }) {
        Text('组件B')
          .height(100)
          .backgroundColor(Color.Green)
      }
    }
    .gutter(12) // 设置间距
    .breakpoints({ 
      value: ['320vp', '600vp'], // 断点:小屏(≤320vp)、中屏(>320vp且≤600vp)
      reference: BreakpointsReference.WindowSize 
    })
  }
}

效果分析

  • 屏幕宽度 ≤ 320vp:每个 GridCol 占满 12 列(整行),两块组件竖排。
  • 屏幕宽度 > 320vp:每个 GridCol 占 6 列(半行),两块组件横排。

方案二:使用 Flex 弹性布局

原理: 通过 Flex 容器的 wrap: FlexWrap.Wrap 属性,允许子组件在空间不足时自动换行。

示例代码

@Entry
@Component
struct FlexibleLayoutExample {
  build() {
    Flex({ 
      direction: FlexDirection.Row, 
      wrap: FlexWrap.Wrap, // 允许换行
      justifyContent: FlexAlign.SpaceBetween 
    }) {
      // 第一块组件
      Text('组件A')
        .width('50%')  // 默认占半行
        .minWidth(100) // 最小宽度限制
        .height(100)
        .backgroundColor(Color.Blue)

      // 第二块组件
      Text('组件B')
        .width('50%')
        .minWidth(100)
        .height(100)
        .backgroundColor(Color.Green)
    }
    .width('100%')
    .padding(12)
  }
}

效果分析

  • 空间充足:两块组件各占 50% 宽度,在同一行横排。
  • 空间不足(如屏幕宽度 < 200vp):由于设置了 minWidth: 100,宽度不足时自动换行,变为竖排。

选择建议

  • GridRow 方案:更适合需要精确响应断点的复杂布局(如多设备适配)。
  • Flex 方案:更简单灵活,适合快速实现动态换行效果。

可以尝试使用Flex组件,

在HarmonyOS Next中,使用自适应布局容器FlexGridRow实现组件根据宽度自动横竖排。
Flexwrap属性设为FlexWrap.Wrap,组件超出容器宽度时自动换行。
GridRow配合GridCol,通过设置不同断点的span值定义响应式列数。
使用constraintSize百分比宽度限制组件尺寸,结合媒体查询断点系统监听宽度变化,动态调整布局方向。

在HarmonyOS Next中,可以通过Flex容器配合wrap属性以及@ohos.mediaquery媒体查询来实现组件根据可用宽度自动切换横排与竖排布局。核心思路是让容器在主轴空间不足时允许子组件换行。

方案一:使用Flex布局的wrap模式(推荐)

这是最简洁、符合声明式开发范式的方法。将两个组件放入一个Flex容器,并设置wrap属性为FlexWrap.Wrap。当主轴(默认为水平方向)空间不足时,第二个组件会自动换行,形成竖排效果。

示例代码:

// 示例ArkTS代码
import { Flex, Text, Column } from '@kit.ArkUI';

@Entry
@Component
struct AdaptiveLayoutExample {
  build() {
    // 使用Flex容器,主轴为水平方向,允许换行
    Flex({ direction: FlexDirection.Row, wrap: FlexWrap.Wrap }) {
      // 第一个组件,设置合适的flexGrow或固定宽度
      Text('组件A')
        .fontSize(20)
        .backgroundColor(Color.Blue)
        .padding(10)
        .flexGrow(1) // 可伸缩,与兄弟组件共享剩余空间
        .constraintSize({ minWidth: 150 }) // 设置最小宽度

      // 第二个组件
      Text('组件B')
        .fontSize(20)
        .backgroundColor(Color.Green)
        .padding(10)
        .flexGrow(1)
        .constraintSize({ minWidth: 150 })
    }
    .width('100%') // 容器宽度占满父组件
    .padding(10)
  }
}

原理:

  • FlexDirection.Row 设置主轴为水平方向,子组件默认尝试横向排列。
  • FlexWrap.Wrap 是关键。当两个子组件的最小宽度之和(本例中为 150 + 150 + 内边距和外边距)超过Flex容器的可用宽度时,第二个Text组件会自动换行到下一行,实现竖排效果。
  • flexGrow(1) 让两个组件在同行时能均分剩余空间。
  • .width('100%') 确保容器宽度与屏幕或父组件宽度同步变化。

方案二:结合媒体查询进行断点控制

如果需要更精确地在特定屏幕宽度下切换布局方向(例如,不仅仅依赖于组件自身的最小宽度,而是希望在某个明确的屏幕断点改变整体排列方向),可以结合媒体查询。

示例代码:

import { Flex, Text, Column } from '@kit.ArkUI';
import { mediaQuery } from '@kit.ArkUI';

@Entry
@Component
struct AdaptiveLayoutWithMediaQuery {
  // 定义一个状态变量,根据媒体查询结果控制布局方向
  @State isVertical: boolean = false;

  aboutToAppear() {
    // 监听屏幕宽度变化,例如当屏幕宽度小于400vp时,切换为竖排
    let listener = mediaQuery.matchMediaSync('(max-width: 400vp)');
    listener.on('change', (result: mediaQuery.MediaQueryResult) => {
      this.isVertical = result.matches; // 如果匹配条件(宽度<=400vp),则isVertical为true
    });
  }

  build() {
    // 根据isVertical状态决定使用Column(竖排)还是Flex Row横排(可换行)
    if (this.isVertical) {
      // 竖排布局
      Column() {
        Text('组件A')
          .fontSize(20)
          .backgroundColor(Color.Blue)
          .padding(10)
          .width('100%')

        Text('组件B')
          .fontSize(20)
          .backgroundColor(Color.Green)
          .padding(10)
          .width('100%')
      }
      .width('100%')
      .padding(10)
    } else {
      // 横排布局(使用允许换行的Flex,作为兜底)
      Flex({ direction: FlexDirection.Row, wrap: FlexWrap.Wrap }) {
        Text('组件A')
          .fontSize(20)
          .backgroundColor(Color.Blue)
          .padding(10)
          .flexGrow(1)
          .constraintSize({ minWidth: 150 })

        Text('组件B')
          .fontSize(20)
          .backgroundColor(Color.Green)
          .padding(10)
          .flexGrow(1)
          .constraintSize({ minWidth: 150 })
      }
      .width('100%')
      .padding(10)
    }
  }
}

总结与选择

  • 追求简单自适应:直接使用方案一(Flex + Wrap)。这是最符合声明式UI设计理念的做法,布局引擎会自动计算空间并决定是否换行,无需手动判断屏幕尺寸。
  • 需要明确的断点控制:如果业务逻辑要求必须在某个精确的屏幕宽度(如400vp)切换布局,而不是单纯因为组件内容放不下,则使用方案二(媒体查询)。它可以实现更复杂的响应式逻辑。

对于你描述的需求“如果能在同一行放置,则横排;如果超出屏幕,则竖排”,方案一完全满足且实现更优雅。只需正确设置父容器的wrap属性以及子组件的constraintSizeflexGrow即可,系统会自动处理换行逻辑。

回到顶部