【问题标题】:How to calculate childAspectRatio for GridView.builder in flutter如何在颤动中计算 GridView.builder 的 childAspectRatio
【发布时间】:2020-10-21 06:34:08
【问题描述】:

类别网格,图像下方显示图像和类别名称

 Widget build(BuildContext context) {
return FutureBuilder(
    future: categoriesService.getCategories(1),
    builder: (BuildContext context, AsyncSnapshot snapshot) {
      if (snapshot.connectionState == ConnectionState.done) {
        if (snapshot.error != null) {
          print('error ${snapshot.error}');
          return Text(snapshot.error.toString());
        }
        // YOUR CUSTOM CODE GOES HERE
        return Container(
          // padding: const EdgeInsets.all(0.0),
          child: GridView.builder(
            physics: NeverScrollableScrollPhysics(),
            shrinkWrap: true,
            gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
              crossAxisCount: 3,
              // childAspectRatio: 19 / 12,
              mainAxisSpacing: 10.0,
              crossAxisSpacing: 10.0,
            ),
            itemCount: snapshot.data.length,
            itemBuilder: (context, index) {
              Category category = snapshot.data[index];
              return Column(
                crossAxisAlignment: CrossAxisAlignment.center,
                mainAxisAlignment: MainAxisAlignment.start,
                children: <Widget>[
                  Container(
                    child: Image.network(
                      category.image,
                      fit: BoxFit.cover,
                    ),
                    decoration: BoxDecoration(
                      border: Border.all(width: 1.0),
                    ),
                  ),
                  Text(category.name)
                ],
              );
            },
          ),
        );
      } else {
        return new CircularProgressIndicator();
      }
    });

}

我的子项目有一个图像和类别名称。如图所示,当前子项溢出,我们无法在图像下方看到类别名称,并且无法删除图像和边框之间的顶部空间。

原创设计在这里

【问题讨论】:

  • 子纵横比基本上是网格的宽度/高度。因此,假设您希望每个网格的宽度为 30,高度为 20,您可以将纵横比设置为 3/2。
  • 还没有解决我的问题。我必须显示 1:1 图像,并且在每个图像的底部要添加一个具有 100 像素高度的完整可用宽度的容器。请建议,我们该怎么做。谢谢。

标签: flutter


【解决方案1】:

您可以使用设备的宽度和高度来动态计算纵横比。我添加了一个基于您的代码示例,展示了如何做到这一点。请注意,您可能需要稍微调整提供的纵横比以满足您的特定要求。

import 'package:flutter/material.dart';

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

class Category {
  String name;
  String image;

  Category({this.name, this.image,});
}

class CategoriesService {
  Future<List<Category>> getCategories(int value) async {
    return <Category>[
      Category(
        name: 'FRESH CHICKEN',
        image: 'https://picsum.photos/400/300',
      ),
      Category(
        name: 'FRESH MUTTON',
        image: 'https://picsum.photos/400/300',
      ),
      Category(
        name: 'HALAL FROZEN FISH',
        image: 'https://picsum.photos/400/300',
      ),
      Category(
        name: '2X STORE',
        image: 'https://picsum.photos/400/300',
      ),
      Category(
        name: 'FROZEN NONVEG DELIGHTS',
        image: 'https://picsum.photos/400/300',
      ),
      Category(
        name: 'FROZEN VEG DELIGHTS',
        image: 'https://picsum.photos/400/300',
      ),
      Category(
        name: 'DAL & PULSES',
        image: 'https://picsum.photos/400/300',
      ),
      Category(
        name: 'SPICES',
        image: 'https://picsum.photos/400/300',
      ),
      Category(
        name: 'DRY FRUITS & NUTS',
        image: 'https://picsum.photos/400/300',
      ),
    ];
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: FutureBuilder(
          future: CategoriesService().getCategories(1),
        builder: (BuildContext context, AsyncSnapshot snapshot) {
          if (snapshot.connectionState == ConnectionState.done) {
            if (snapshot.error != null) {
              print('error ${snapshot.error}');
              return Text(snapshot.error.toString());
            }
            // YOUR CUSTOM CODE GOES HERE
            return Container(
              // padding: const EdgeInsets.all(0.0),
              child: GridView.builder(
                physics: NeverScrollableScrollPhysics(),
                shrinkWrap: true,
                gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                  crossAxisCount: 3,
                  childAspectRatio: MediaQuery.of(context).size.width /
                      (MediaQuery.of(context).size.height / 1.4),
                  mainAxisSpacing: 10.0,
                  crossAxisSpacing: 10.0,
                ),
                itemCount: snapshot.data.length,
                itemBuilder: (context, index) {
                  Category category = snapshot.data[index];
                  return Column(
                    crossAxisAlignment: CrossAxisAlignment.center,
                    mainAxisAlignment: MainAxisAlignment.start,
                    children: <Widget>[
                      Container(
                        child: Image.network(
                          category.image,
                          fit: BoxFit.cover,
                        ),
                        decoration: BoxDecoration(
                          border: Border.all(width: 1.0),
                        ),
                      ),
                      Padding(
                        padding: const EdgeInsets.only(
                          top: 8.0,
                        ),
                        child: Text(
                          category.name,
                          textAlign: TextAlign.center,
                        ),
                      )
                    ],
                  );
                },
              ),
            );
          } else {
            return new CircularProgressIndicator();
          }
        }),
      ),
    );
  }
}

如果您还没有看过以下答案,您可能会发现以下答案对有关 GridView 小部件的纵横比的更多信息很有用。

【讨论】:

  • 我必须以 1:1(宽:高)的比例显示网格,但高度应该额外增加 100 像素。例如。我能怎么做?请建议。谢谢。
【解决方案2】:

我找到了一种方法,可以动态地将最大孩子的纵横比设置为我们的 Grid 视图。 它是如何工作的 ? 首先请看这个答案。我们如何在构建过程中使用overlayEntery找到小部件的大小

How to get a height of a Widget?

之后,我们在 childAspectRatio 中为我们的网格视图设置正确的纵横比(使用 overlayEntery 测量)。

希望对你有所帮助。

我举个例子……

https://dartpad.dev/4821d71ec618d7d1f1f92f27458fde61



import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}
class GridItemModel {
  String longtext;
  GlobalKey itemKey;
  double width;
  double height;
  GridItemModel(this.longtext) {
    itemKey = GlobalKey();
  }
}
class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(),
    );
  }

}
class MyHomePage extends StatefulWidget{
  @override
  State<StatefulWidget> createState() {
    return _StateHomePage();
  }

}

class _StateHomePage extends State<MyHomePage> {
  // this first assign very important don't change it .
  // if you change this part overlayEntry cant find biggest widget correctly .(cant see not scrolled items.)
  // for test change to 1/1 and see what happening.
  var myDynamicAspectRatio = 1000 / 1;
  OverlayEntry sticky;
  List<GridItemModel> myGridList = new List();
  double maxHeight = 0;
  double maxWidth = 0;

  @override
  void initState() {
    if (sticky != null) {
      sticky.remove();
    }
    sticky = OverlayEntry(
      builder: (context) => stickyBuilder(context),
    );

    WidgetsBinding.instance.addPostFrameCallback((_) {
      Overlay.of(context).insert(sticky);
      setState(() {});
    });
    super.initState();
  }

  @override
  void dispose() {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      sticky.remove();
    });
    super.dispose();
  }


  @override
  Widget build(BuildContext context) {
    final title = 'Grid List';
    return MaterialApp(
      title: title,
      home: Scaffold(
        appBar: AppBar(
          title: Text(title),
        ),
        body: GridView.count(
            crossAxisCount: 2,
            childAspectRatio: myDynamicAspectRatio,
            children: List.generate(20, (index) {
              myGridList.add(new GridItemModel(longTextMaker(index)));
              return Column(
                mainAxisSize: MainAxisSize.min,
                children: <Widget>[
                  Container(
                    key: myGridList[index].itemKey,
                    decoration: BoxDecoration(
                      border: Border.all(color: Colors.black),
                      color: Colors.teal[index*100]
                    ),
                    child: Text(
                      'Item $index' + myGridList[index].longtext,
                      style: Theme.of(context).textTheme.headline5,
                    ),
                  ),
                ],
              );
            }),
          ),
        ),
    );
  }
  String longTextMaker(int count){
    String  result = "longText";
    for(int i = 0 ; i < count; i++){
      result += "longText" ;
    }
    return result;
  }
  shouldUpdateGridList(){
    bool isChanged =false;
    for(GridItemModel gi in myGridList) {
      if(gi.width != null) {
        if (gi.height > maxHeight) {
          maxHeight = gi.height;
          maxWidth = gi.width;
          isChanged = true;
        }
      }
    }
    if(isChanged) {
        myDynamicAspectRatio = maxWidth / maxHeight;
        print("AspectRatio" + myDynamicAspectRatio.toString());
    }
  }

  Widget stickyBuilder(BuildContext context) {
    for(GridItemModel gi in myGridList) {
      if(gi.width == null) {
        final keyContext = gi.itemKey.currentContext;
        if (keyContext != null) {
          final box = keyContext.findRenderObject() as RenderBox;
          print(box.size.height);
          print(box.size.width);
          gi.width = box.size.width;
          gi.height = box.size.height;
        }
      }
    }
    shouldUpdateGridList();
    return Container();
  }
}

【讨论】:

  • 还没有解决我的问题。我必须显示 1:1 图像,并且在每个图像的底部要添加一个具有 100 像素高度的完整可用宽度的容器。请建议,我们该怎么做。谢谢。
【解决方案3】:

子纵横比基本上是网格相对于设备的宽度/高度。

假设您希望每个网格的宽度为 30,高度为 20,您可以将纵横比设置为 3/2。

我建议你直接从 Flutter 团队观看这个video。虽然它是关于 AspectRatio 小部件的,但关于设置 aspectRatio 的部分适用于这个问题

【讨论】:

  • 还没有解决我的问题。我必须显示 1:1 图像,并且在每个图像的底部要添加一个具有 100 像素高度的完整可用宽度的容器。请建议,我们该怎么做。谢谢。
【解决方案4】:

您可以像这样在 GridView.builder 中提供 childAspectRatio:

GridView.builder(
  gridDelegate:
     SliverGridDelegateWithFixedCrossAxisCount(
         crossAxisCount:3,childAspectRatio: (150.0 / 220.0)
     )
)

【讨论】:

  • stackoverflow 中的代码块语法不同,可以使用帮助查看代码块语法
猜你喜欢
  • 2021-11-29
  • 2019-05-05
  • 1970-01-01
  • 2021-11-25
  • 2021-11-24
  • 2021-10-06
  • 2020-11-29
  • 2019-06-16
  • 2020-05-05
相关资源
最近更新 更多