GridView 高度适合孩子的高度颤动

问题描述 投票:0回答:3

我对Flutter中GridView的使用感到困惑。我想显示功能列表及其费率。功能组件/小部件的高度并没有那么大,但是当我将它们放置在 GridView 中时,每个单元格的高度比所需的要大得多。

如何控制每个箱子的高度以适合孩子的身高?

这是我的代码:

import 'package:flutter/material.dart';
import 'package:project/Components/ReviewComps/AttributeRatings.dart';
    
class ReviewPage extends StatelessWidget {
      const ReviewPage({Key? key}) : super(key: key);
      @override
      Widget build(BuildContext context) {
        return Scaffold(
            body: SingleChildScrollView(
          child: Container(
            padding: const EdgeInsets.all(20),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisAlignment: MainAxisAlignment.start,
              children: const <Widget>[
                AttributeRatings(),
              ],
            ),
          ),
        ));
      }
    }

这是我的 GridView,它产生了问题。

import 'package:flutter/material.dart';

class AttributeRatings extends StatelessWidget {
  const AttributeRatings({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    var featureList = [
      _featureItems(4),
      _featureItems(3.2),
      _featureItems(1),
    ];
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        const Text("Features average rating"),
        GridView.count(
          crossAxisCount: 2,
          crossAxisSpacing: 20,
          shrinkWrap: true,
          physics: const NeverScrollableScrollPhysics(),
          children: featureList,
        ),
      ],
    );
  }
}

Container _featureItems(double rate) {
  return Container(
    color: Colors.red,
    child: Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            const Text('Feature'),
            Text(rate.toString()),
          ],
        ),
        Stack(
          children: [
            Container(
              height: 2,
              width: double.infinity,
              color: const Color(0xffDBDFED),
            ),
            FractionallySizedBox(
              widthFactor: rate / 5,
              child: Container(
                height: 2,
                color: const Color(0xff39B0EA),
              ),
            )
          ],
        )
      ],
    ),
  );
}
flutter gridview
3个回答
0
投票

您可以给

childAspectRatio
自定义高度如下

import 'package:flutter/material.dart';

class AttributeRatings extends StatelessWidget {
  const AttributeRatings({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    var featureList = [
      _featureItems(4),
      _featureItems(3.2),
      _featureItems(1),
    ];
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        const Text("Features average rating"),
        GridView.count(
          crossAxisCount: 2,
          crossAxisSpacing: 20,
          childAspectRatio: 4,//You may have to calculate based on screen size
          shrinkWrap: true,
          physics: const NeverScrollableScrollPhysics(),
          children: featureList,
        ),
      ],
    );
  }
}

Container _featureItems(double rate) {
  return Container(
    color: Colors.red,
    child: Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            const Text('Feature'),
            Text(rate.toString()),
          ],
        ),
        Stack(
          children: [
            Container(
              height: 2,
              width: double.infinity,
              color: const Color(0xffDBDFED),
            ),
            FractionallySizedBox(
              widthFactor: rate / 5,
              child: Container(
                height: 2,
                color: const Color(0xff39B0EA),
              ),
            )
          ],
        )
      ],
    ),
  );
}

0
投票

我发现的解决方案非常复杂,但我将网格视图更改为列表视图并将行放入其中。最困难的是使用奇数长度列表,这是我的解决方案:

import 'package:flutter/material.dart';

class AttributeRatings extends StatelessWidget {
  const AttributeRatings({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    var featureList = [4, 3.2, 4, 2, 3.2];
    double nbRows = featureList.length % 2 == 0
        ? (featureList.length / 2)
        : (featureList.length / 2) + 1;
    var reworkedFeatureList = [];
    if (featureList.length % 2 == 0) {
      for (var i = 0; i < (featureList.length - 1) / 2; i++) {
        reworkedFeatureList.add([featureList[i * 2], featureList[(i * 2) + 1]]);
      }
    } else {
      final retVal = featureList.removeLast();
      for (var i = 0; i < (featureList.length - 1) / 2; i++) {
        reworkedFeatureList.add([featureList[i * 2], featureList[(i * 2) + 1]]);
      }
      reworkedFeatureList.add([retVal, -1]);
    }
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        const Text("Features average rating"),
        ListView.separated(
          separatorBuilder: (context, index) {
            return const SizedBox(height: 12);
          },
          itemCount: nbRows.toInt(),
          shrinkWrap: true,
          physics: const NeverScrollableScrollPhysics(),
          itemBuilder: (context, index) =>
              _featureItemsRow(reworkedFeatureList[index]),
        ),
      ],
    );
  }
}

Row _featureItemsRow(var rates) {
  return Row(
    children: [
      Expanded(
          child: Padding(
        padding: const EdgeInsets.only(right: 10.0),
        child: _featureItem(rates[0].toDouble()),
      )),
      Expanded(
          child: Padding(
        padding: const EdgeInsets.only(left: 10.0),
        child: _featureItem(rates[1].toDouble()),
      )),
    ],
  );
}

Column _featureItem(double rate) {
  if (rate == -1) {
    return Column();
  } else {
    return Column(
      children: [
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            const Text('Feature'),
            Text(rate.toString()),
          ],
        ),
        Stack(
          children: [
            Container(
              height: 2,
              width: double.infinity,
              color: const Color(0xffDBDFED),
            ),
            FractionallySizedBox(
              widthFactor: rate / 5,
              child: Container(
                height: 2,
                color: const Color(0xff39B0EA),
              ),
            )
          ],
        )
      ],
    );
  }
}

0
投票

我有一个类似的问题,我在

GridView.builder
内有一个
SingleChildScrollView
。现在的问题是你不能在
GridView
内创建
SingleChildScrollView
因为两者都会尝试占用尽可能多的可用空间,这使得高度无界/无限。

所以解决方案是用

GridView
包裹
SizedBox
,我总是更喜欢使用
GridView.Builder

现在的实际问题是,“当列表是动态时,我如何知道

SizedBox
的大小?”

所以我编写了这段代码,其逻辑是根据

SizedBox
childAspectRatio
 属性动态计算 
GridView

的高度
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(title: 'Dynamic GridView', home: Home());
  }
}

class Home extends StatelessWidget {
  const Home({super.key});

  @override
  Widget build(BuildContext context) {
    final double width = MediaQuery.of(context).size.width;
    final double height = MediaQuery.of(context).size.height;
    return Scaffold(
      body: SingleChildScrollView(
        child: Column(
          children: [
            itemGrid(width),
          ],
        ),
      ),
    );
  }

  Widget itemGrid(double width) {
    const int count = 16;
    const int itemsPerRow = 2;
    const double ratio = 1 / 1;
    const double horizontalPadding = 0;
    final double calcHeight = ((width / itemsPerRow) - (horizontalPadding)) *
        (count / itemsPerRow).ceil() *
        (1 / ratio);
    return SizedBox(
      width: width,
      height: calcHeight,
      child: GridView.builder(
        padding: const EdgeInsets.symmetric(horizontal: horizontalPadding),
        itemCount: count,
        physics: const NeverScrollableScrollPhysics(),
        shrinkWrap: true,
        gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
            mainAxisSpacing: 0,
            crossAxisSpacing: 0,
            crossAxisCount: itemsPerRow,
            childAspectRatio: ratio),
        itemBuilder: (context, index) {
          return SizedBox(
            child: Card(
              clipBehavior: Clip.hardEdge,
              child: Column(
                children: [
                  Expanded(
                      child: Image.network(
                          "https://picsum.photos/200?${DateTime.now().millisecondsSinceEpoch.toString()}")),
                  const Padding(
                    padding: EdgeInsets.symmetric(horizontal: 4.0),
                    child: Text(
                      "Lorem Ipsum is a dummy text, lorem ipsum",
                      maxLines: 3,
                      overflow: TextOverflow.ellipsis,
                      style:
                          TextStyle(fontSize: 10, fontWeight: FontWeight.bold),
                      textAlign: TextAlign.start,
                    ),
                  ),
                ],
              ),
            ),
          );
        },
      ),
    );
  }
}

指向工作 Dart 要点的链接 - https://dartpad.dev/?id=05ba8804b19a2978a087c68622000a01

说明

  • count
    是项目总数或
    itemCount

  • itemsPerRow
    是一行中的项目数或
    crossAxisCount

  • ratio
    childAspectRatio
    GridView
    属性,通常用于设置网格内项目的大小。
    ratio
    计算为宽度/高度。
  • horizontalPadding
    是给
    GridView
    的水平填充(在垂直列表的情况下)
  • calcHeight
    SizedBox
    的计算高度,因此在动态列表的情况下不需要给出固定高度。
© www.soinside.com 2019 - 2024. All rights reserved.