You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter实现类Pinterest固定宽度自适应网格布局的技术问题

实现固定宽度、自适应列数的瀑布流布局

针对你需要固定容器宽度、高度各异,且列数随屏幕尺寸自适应的需求,flutter_staggered_grid_view的Masonry方案确实不适用(它会均分列宽),可以通过自定义布局来实现,核心思路是动态计算列数并将容器分配到高度最小的列中:

核心实现步骤

  1. 动态计算列数:根据屏幕宽度、容器固定宽度和间距,计算当前能容纳的列数
  2. 分配容器到列:维护每列的当前总高度,每次将新容器添加到高度最小的列
  3. 适配屏幕变化:通过LayoutBuilder监听父容器尺寸变化,自动重新计算列数并重建布局

代码示例

import 'package:flutter/material.dart';

class FixedWidthMasonry extends StatefulWidget {
  final double itemWidth;
  final double spacing;
  final List<Widget> items;

  const FixedWidthMasonry({
    super.key,
    required this.itemWidth,
    required this.spacing,
    required this.items,
  });

  @override
  State<FixedWidthMasonry> createState() => _FixedWidthMasonryState();
}

class _FixedWidthMasonryState extends State<FixedWidthMasonry> {
  late List<double> columnHeights;
  late int columnCount;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    _calculateColumns();
  }

  void _calculateColumns() {
    final screenWidth = MediaQuery.of(context).size.width;
    // 计算列数,确保间距正确分配
    columnCount = ((screenWidth + widget.spacing) / (widget.itemWidth + widget.spacing)).floor();
    columnCount = columnCount < 1 ? 1 : columnCount;
    columnHeights = List.filled(columnCount, 0.0);
  }

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        _calculateColumns();
        // 初始化各列的容器列表
        final List<List<Widget>> columnItems = List.generate(columnCount, (_) => []);
        
        for (final item in widget.items) {
          // 找到当前高度最小的列
          final minIndex = columnHeights.indexOf(columnHeights.reduce((a, b) => a < b ? a : b));
          columnItems[minIndex].add(
            Padding(
              padding: EdgeInsets.only(
                bottom: widget.spacing,
                right: minIndex != columnCount - 1 ? widget.spacing : 0,
              ),
              child: _MeasuredItem(
                onHeightChange: (height) {
                  // 更新对应列的高度
                  setState(() {
                    columnHeights[minIndex] = height + widget.spacing;
                  });
                },
                child: item,
              ),
            ),
          );
        }

        return SingleChildScrollView(
          child: Row(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: columnItems.map((items) {
              return SizedBox(
                width: widget.itemWidth,
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: items,
                ),
              );
            }).toList(),
          ),
        );
      },
    );
  }
}

// 用于测量容器实际高度的组件
class _MeasuredItem extends StatefulWidget {
  final Widget child;
  final Function(double height) onHeightChange;

  const _MeasuredItem({
    required this.child,
    required this.onHeightChange,
  });

  @override
  State<_MeasuredItem> createState() => _MeasuredItemState();
}

class _MeasuredItemState extends State<_MeasuredItem> {
  final _key = GlobalKey();

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      _measureHeight();
    });
  }

  void _measureHeight() {
    final renderBox = _key.currentContext?.findRenderObject() as RenderBox?;
    if (renderBox != null) {
      widget.onHeightChange(renderBox.size.height);
    }
  }

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      key: _key,
      child: widget.child,
    );
  }
}

使用方式

FixedWidthMasonry(
  itemWidth: 150, // 固定容器宽度
  spacing: 10, // 容器间距
  items: [
    Container(height: 120, color: Colors.red),
    Container(height: 180, color: Colors.blue),
    Container(height: 90, color: Colors.green),
    // 更多高度各异的容器...
  ],
)

关键说明

  • 用_MeasuredItem组件自动获取每个容器的实际渲染高度,确保列高度计算准确,适配动态内容(比如文本、图片)
  • LayoutBuilder会在屏幕尺寸变化时触发重建,自动调整列数,完美适配不同屏幕
  • 完全保持容器宽度固定,不会像Masonry网格那样拉伸或压缩容器宽度

内容的提问来源于stack exchange,提问作者Milad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 03:37:44