HarmonyOS鸿蒙Next Grid网格布局如何实现瀑布流效果?网格布局开发指南

HarmonyOS鸿蒙Next Grid网格布局如何实现瀑布流效果?网格布局开发指南 armonyOS 5.0,DevEco Studio 5.0

  • 需要实现图片瀑布流展示效果
  • 不清楚Grid组件的配置方法
  • 希望了解不等高网格的实现方式

希望了解HarmonyOS Grid组件的使用方法,实现瀑布流和网格布局

3 回复

1. 基础网格布局

@Entry
@Component
struct GridPage {
  @State items: number[] = Array.from({ length: 20 }, (_, i) => i + 1)

  build() {
    Grid() {
      ForEach(this.items, (item: number) => {
        GridItem() {
          Column() {
            Text(`${item}`)
              .fontSize(16)
              .fontColor($r('app.color.text_primary'))
          }
          .width('100%')
          .height(100)
          .backgroundColor($r('app.color.surface'))
          .borderRadius(12)
          .justifyContent(FlexAlign.Center)
        }
      }, (item: number) => item.toString())
    }
    .columnsTemplate('1fr 1fr')  // 两列等宽
    .columnsGap(12)
    .rowsGap(12)
    .padding(16)
    .backgroundColor($r('app.color.background'))
  }
}

2. 瀑布流布局(WaterFlow)

@Observed
class WaterFlowItem {
  id: string
  height: number
  color: string

  constructor(id: string, height: number, color: string) {
    this.id = id
    this.height = height
    this.color = color
  }
}

@Entry
@Component
struct WaterFlowPage {
  @State items: WaterFlowItem[] = []

  aboutToAppear(): void {
    const colors = ['#36e27b', '#3b82f6', '#f97316', '#a855f7', '#ef4444']
    this.items = Array.from({ length: 30 }, (_, i) => {
      return new WaterFlowItem(
        i.toString(),
        100 + Math.random() * 150,  // 随机高度
        colors[i % colors.length]
      )
    })
  }

  build() {
    WaterFlow() {
      ForEach(this.items, (item: WaterFlowItem) => {
        FlowItem() {
          Column() {
            Text(item.id)
              .fontSize(20)
              .fontWeight(FontWeight.Bold)
              .fontColor(Color.White)
          }
          .width('100%')
          .height(item.height)
          .backgroundColor(item.color)
          .borderRadius(12)
          .justifyContent(FlexAlign.Center)
        }
      }, (item: WaterFlowItem) => item.id)
    }
    .columnsTemplate('1fr 1fr')
    .columnsGap(12)
    .rowsGap(12)
    .padding(16)
    .backgroundColor($r('app.color.background'))
  }
}

3. 图片瀑布流

interface ImageItem {
  id: string
  url: string
  aspectRatio: number
}

@Entry
@Component
struct ImageWaterFlowPage {
  @State images: ImageItem[] = []

  aboutToAppear(): void {
    // 模拟图片数据
    this.images = [
      { id: '1', url: 'https://example.com/1.jpg', aspectRatio: 1.5 },
      { id: '2', url: 'https://example.com/2.jpg', aspectRatio: 0.8 },
      // ...
    ]
  }

  build() {
    WaterFlow() {
      ForEach(this.images, (item: ImageItem) => {
        FlowItem() {
          Image(item.url)
            .width('100%')
            .aspectRatio(item.aspectRatio)
            .objectFit(ImageFit.Cover)
            .borderRadius(12)
        }
      }, (item: ImageItem) => item.id)
    }
    .columnsTemplate('1fr 1fr')
    .columnsGap(8)
    .rowsGap(8)
    .padding(16)
  }
}

4. Grid常用配置

Grid()
  .columnsTemplate('1fr 1fr 1fr')      // 三列等宽
  .rowsTemplate('1fr 1fr')             // 两行等高
  .columnsGap(12)                      // 列间距
  .rowsGap(12)                         // 行间距
  .scrollBar(BarState.Off)             // 隐藏滚动条
  .cachedCount(4)                      // 缓存数量

5. 跨行跨列

GridItem() {
  // 内容
}
.columnStart(0)    // 起始列
.columnEnd(1)      // 结束列(跨2列)
.rowStart(0)       // 起始行
.rowEnd(0)         // 结束行

更多关于HarmonyOS鸿蒙Next Grid网格布局如何实现瀑布流效果?网格布局开发指南的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


鸿蒙Next的Grid组件可通过自定义布局管理器实现瀑布流。在GridItemContainer中重写onMeasure和onLayout方法,动态计算每个网格项的位置和大小。使用GridItemProvider管理数据源,结合GridItem的宽高自适应。通过设置不同的列宽和行高参数,实现错落排列的瀑布流视觉效果。

在HarmonyOS Next中,使用Grid组件实现瀑布流效果,核心在于结合其列数配置与子项的自适应高度。Grid本身是等宽布局,瀑布流的“不等高”需要子组件内容撑开高度来实现。

以下是关键步骤和代码示例:

  1. Grid组件基础配置: 设置columnsTemplate为固定列数(如'1fr 1fr'代表两列),rowsTemplate'auto',让行高自适应内容。同时启用layoutDirectionGridDirection.Row(默认值,按行优先排列)。

    Grid() {
      // ... 子项内容
    }
    .columnsTemplate('1fr 1fr') // 定义列数,例如2列
    .rowsTemplate('auto')       // 行高自适应内容
    .layoutDirection(GridDirection.Row)
    .width('100%')
    
  2. 子项内容与高度自适应: 瀑布流效果依赖于每个网格子项内容(尤其是图片)具有不同的高度。将图片或内容组件放入GridItem()中,不设置固定高度,依靠内容自身高度或aspectRatio(宽高比)属性来撑开GridItem,从而实现错落布局。

    ForEach(this.imageData, (item: ImageData) => {
      GridItem() {
        Column() {
          Image(item.src)
            .aspectRatio(item.ratio) // 关键:通过宽高比控制图片显示高度
            .width('100%')
            .objectFit(ImageFit.Cover)
          Text(item.title)
            // ... 文本样式
        }
        .width('100%')
        // 注意:Column不设置固定高度,由内部Image和Text撑开
      }
    })
    
  3. 数据模型: 数据源中应包含计算或预设的宽高比(ratio),这是实现高度差异的关键。

    class ImageData {
      src: ResourceStr;
      ratio: number; // 宽高比,用于.aspectRatio()
      title: string;
    }
    

重要说明

  • 瀑布流实现原理:Grid按行优先顺序排列,每行的单元格等高。但由于设置了rowsTemplate('auto')且每个GridItem内容高度不同,Grid会自动将内容分配至最短的列,从而实现视觉上的错落瀑布流效果。这要求子项高度是动态的。
  • 性能考虑:对于大量图片,建议使用LazyForEach进行列表渲染优化,并配合图片缓存策略。
  • 网格布局(等高等宽)只需为子项设置固定尺寸或比例即可。

这种方法直接利用Grid的流式布局能力,无需复杂计算即可实现基础的瀑布流展示。

回到顶部