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

Flutter中GridView仅显示一列:如何实现数据左右填充排列?

解决Flutter中JSON数据仅单列显示,实现网格左右填充的问题

你当前的问题根源在于用ListView.builder包裹了每个单独的GridView——这相当于每一条数据都生成了一个只有2列的小网格,自然会变成单列排列。正确的做法是直接用GridView.builder来替代ListView,让整个列表本身就是网格布局,这样数据就会从左到右自动填充了。

修改步骤:

  • 移除_getListViewWidget里的ListView,换成GridView.builder
  • 配置GridView的crossAxisCount(你想要的列数,比如2),以及其他布局参数
  • 调整_buildLostItems方法,直接返回Card即可,不需要再嵌套GridView

修正后的完整代码:

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:elegal_dart/models/items.dart';
import 'package:elegal_dart/services/api.dart';

class LostPage extends StatefulWidget {
  @override
  _LostPage createState() => new _LostPage();
}

class _LostPage extends State<LostPage> {
  List<Item> _items = [];

  @override
  void initState() {
    super.initState();
    _loadLostItems();
  }

  _loadLostItems() async {
    String fileData = await DefaultAssetBundle.of(context).loadString("assets/items.json");
    setState(() {
      _items = ItemApi.allItemsFromJson(fileData);
    });
    print(_items.toString());
  }

  Widget _buildLostItems(BuildContext context, int index) {
    Item item = _items[index];
    // 直接返回Card,不再嵌套GridView
    return Card(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Expanded(
            child: Stack(
              fit: StackFit.expand,
              children: <Widget>[
                Container(
                  height: MediaQuery.of(context).size.height / 4,
                  width: MediaQuery.of(context).size.height / 2.5,
                  child: DecoratedBox(
                    decoration: BoxDecoration(
                      image: DecorationImage(
                        image: NetworkImage(item.item_DispPic),
                        fit: BoxFit.cover),
                    ),
                  ),
                ),
                Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Align(
                    alignment: FractionalOffset.topLeft,
                    child: CircleAvatar(
                      backgroundColor: Colors.redAccent,
                      radius: 15.0,
                      child: Text(
                        "NEW",
                        textScaleFactor: 0.5,
                      ),
                    ),
                  ),
                ),
                Align(
                  alignment: FractionalOffset.topRight,
                  child: Container(
                    color: Colors.blueAccent,
                    height: 35.0,
                    width: 35.0,
                    child: Center(
                      child: Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: <Widget>[
                          Icon(Icons.account_circle),
                          Text(
                            "1P",
                            textScaleFactor: 0.5,
                          ),
                        ],
                      ),
                    ),
                  ),
                ),
              ],
            ),
          ),
          Center(
            child: Container(
              padding: const EdgeInsets.all(8.0),
              alignment: FractionalOffset.bottomCenter,
              child: Text(
                "MEGADISH",
                style: TextStyle(
                  fontWeight: FontWeight.w700,
                ),
              ),
            ),
          ),
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: <Widget>[
              FlatButton(
                child: Text(
                  "Add To Cart",
                  style: TextStyle(color: Colors.grey[500]),
                ),
                onPressed: () => null,
              ),
              Text(
                "\$5",
                style: TextStyle(color: Colors.grey[500]),
              )
            ],
          )
        ],
      ),
    );
  }

  Widget _getAppTitleWidget() {
    return new Text(
      'Lost Items',
      style: new TextStyle(
        color: Colors.white,
        fontWeight: FontWeight.bold,
        fontSize: 32.0,
      ),
    );
  }

  Widget _buildBody() {
    return new Container(
      margin: const EdgeInsets.fromLTRB(
        8.0,
        56.0,
        8.0,
        0.0
      ),
      child: new Column(
        children: <Widget>[
          //_getAppTitleWidget(),
          _getGridViewWidget() // 替换成网格组件
        ],
      ),
    );
  }

  Future<Null> refresh() {
    _loadLostItems();
    return new Future<Null>.value();
  }

  Widget _getGridViewWidget() {
    return new Flexible(
      child: new RefreshIndicator(
        onRefresh: refresh,
        // 用GridView.builder替代ListView
        child: new GridView.builder(
          physics: const AlwaysScrollableScrollPhysics(),
          itemCount: _items.length,
          gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 2, // 设置列数为2
            crossAxisSpacing: 8.0, // 列之间的间距
            mainAxisSpacing: 8.0, // 行之间的间距
          ),
          itemBuilder: _buildLostItems
        )
      )
    );
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      backgroundColor: Colors.blue,
      body: _buildBody(),
    );
  }
}

关键修改说明:

  • 把原来的_getListViewWidget改成_getGridViewWidget,使用GridView.builder来构建网格布局
  • 通过SliverGridDelegateWithFixedCrossAxisCount设置列数、行列间距,精准控制网格的排列样式
  • _buildLostItems方法不再返回嵌套的GridView,直接返回单个Card组件,由GridView统一负责这些Card的左右填充排列

这样修改后,你的JSON数据就会按照2列的布局从左到右依次填充了,完美解决单列显示的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:00:47