【问题标题】:Constrain Column's maxWidth with a specific child's width in Flutter?约束列的最大宽度与 Flutter 中特定子项的宽度?
【发布时间】:2020-11-15 01:54:42
【问题描述】:

必须连续显示 3 个项目:图像和下面的描述,所以它基本上是 Columns 的 Row。描述大小各不相同,可以超过或小于图像的宽度。如果需要,这些图像必须均匀排列,说明多行。

所以朴素的代码大致是这样的:

@override
  Widget build(BuildContext context) => Row(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: <Widget>[
          for (final item in items)
            Column(
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[
                Image.asset(item.depiction),
                Text(
                  item.name,
                  textAlign: TextAlign.center,
                ),
              ],
            )
        ],
      );

问题是Column 的大小是由文本大小的宽度决定的,如果它超过了图像的大小,那么Row 中的图像间隔不均匀。我看到的解决方案是将Column 的宽度限制为Image 的宽度,例如使用某种Builder 小部件,但它似乎根本不对。

我尝试用Expanded 包裹所有Row 的孩子,但随后spaceAround 没有任何效果,因为所有孩子的大小都为Row 的1/3,并且此间距至关重要,其中可用空间的值应为row.length - 3 * image.size(伪代码给出一个总体思路)。用Flexible 包裹Column 并将stretch 交叉轴对齐设置为相同的Column 会产生相同的效果——Column 的大小为Row 长度的1/3。

Text 宽度限制为图像宽度为maxWidth 的正确方法是什么?

图片:

在第三个Row 中它可以正常工作,因为Text 的宽度小于图像的宽度。

第二个RowText的宽度大于图片的宽度,所以Column的大小是一行文字宽度,图片的布局不等于前一个。

第一个Row 是我希望第二个Row 呈现的方式,在此示例中,它只是分离的(\n) 描述,导致我寻求的视觉效果。

【问题讨论】:

  • 您可以添加图片以便我正确理解您的问题吗?
  • @HardikKumar 添加了
  • 你为什么不用gridview。对于图片上显示的布局,gridview 是最好的方法
  • @delmin 上面有一个逻辑可以解释为here is a row of items of the same category, please pick one of them,所以Row(或水平ListView)对于这样的组织来说在这里很方便。不过可以改。但我看不出它对间距有什么帮助,因为需要自适应spaceAround 策略,并且“自适应”是指它计算可用空间(layout.width - image.width * 3)并相应地为子空间留出空间(这样我们得到freeSpace / 4; image1; freeSpace / 4; image2; freeSpace / 4; image3; freeSpace / 4); is it possible with GridView`?
  • 据我正确理解,gridview 是您想​​要的。如果您希望所有列的大小完全相同,我相信 gridview 可以实现所有这些。那 gridview 的作用......我可能误解了你的问题,但我仍然相信 gridview 是要走的路

标签: flutter dart flutter-layout


【解决方案1】:

这是我在堆栈溢出中看到的第三个问题。

我刚刚为它写了一个包:https://pub.dev/packages/flex_with_main_child

您可以将 Column 替换为来自 flex_with_main_child 的 ColumnWithMainChild

Column(
  mainAxisSize: MainAxisSize.min,
  mainChild: Image.asset(item.depiction),
  childrenBelow: <Widget>[
    Text(
      item.name,
      textAlign: TextAlign.center,
    ),
  ],
)

【讨论】:

    【解决方案2】:

    所以我现在最终得到了一个我不满意的非常老套的解决方案,但仍然将它发布给寻求相同答案的人:

    typedef ImageBasedBuilder = Widget Function(
        BuildContext context, ImageInfo image);
    
    class ImageInfoBasedWidget<T> extends StatefulWidget {
      final ImageProvider<T> provider;
      final ImageBasedBuilder builder;
    
      const ImageInfoBasedWidget({
        @required this.provider,
        @required this.builder,
        Key key,
      }) : super(key: key);
    
      @override
      _ImageInfoBasedWidgetState<T> createState() =>
          _ImageInfoBasedWidgetState<T>();
    }
    
    class _ImageInfoBasedWidgetState<T>
        extends State<ImageInfoBasedWidget<T>> {
      ImageStream _imageStream;
      ImageStreamListener _streamListener;
      ImageInfo _imageInfo;
    
      @override
      void didChangeDependencies() {
        super.didChangeDependencies();
        _resolveImage();
      }
    
      @override
      void didUpdateWidget(ImageInfoBasedWidget<T> oldWidget) {
        super.didUpdateWidget(oldWidget);
        if (oldWidget.provider != widget.provider) {
          _resolveImage();
        }
      }
    
      @override
      void dispose() {
        _imageStream.removeListener(_streamListener);
        super.dispose();
      }
    
      void _resolveImage() {
        final ImageStream oldImageStream = _imageStream;
        _imageStream =
            widget.provider.resolve(createLocalImageConfiguration(context));
        if (_imageStream.key != oldImageStream?.key) {
          final ImageStreamListener listener = ImageStreamListener(_provideImage);
          oldImageStream?.removeListener(listener);
          _imageStream.addListener(listener);
        }
      }
    
      void _provideImage(ImageInfo imageInfo, bool syncCall) =>
          setState(() => _imageInfo = imageInfo);
    
      @override
      Widget build(BuildContext context) {
        if (_imageInfo == null) {
          return Container();
        } else {
          return widget.builder(context, _imageInfo);
        }
      }
    }
    
    

    这很简单——我们只是获得了稍后将由构建器对象函数使用的图像配置。我们可以使用ConstrainedBox 放置文本约束,这将具有maxWidthimageInfo.image.width

    【讨论】:

    • 可能有点骇人听闻,但只有这样的事情看起来才是前进的方向。因为在不知何故知道图像的宽度的情况下,似乎没有其他办法。 IntrinsicWidth 似乎根据最宽的孩子调整宽度,而不是最不宽的孩子。我搜索了可以根据最小宽度的孩子强制宽度的东西,但我找不到任何东西。
    • 是的,昨天研究主题时得到了相同的结果。感觉它可以做得更简单并且框架支持它现成的并没有消失:\
    【解决方案3】:

    我想这就是你想要的:

    Image 1

    Image 2

    Image 3

    代码:

    class ClassName extends StatelessWidget {  
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          backgroundColor: Colors.grey[200],
    
          appBar: AppBar(
            backgroundColor: Colors.white,
            centerTitle: true,
            title: Text('This is the solution', style: TextStyle(color: Colors.black, fontSize: 18.0),),
          ),
    
          body: Column(
            children: [
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: <Widget>[
                  col(context),
                  col(context),
                  col(context),
                ],
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: <Widget>[
                  col(context),
                  col(context),
                  col(context),
                ],
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: <Widget>[
                  col(context),
                  col(context),
                  col(context),
                ],
              ),
            ],
          ),
        );
      }
    }
    
    col(context){
      return SizedBox(
        width: MediaQuery.of(context).size.width*0.3,
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            SizedBox(height: 100.0, child: Image.asset('assets/02.jpg')),
            Text('smith smith smith smith smith smith smith', textAlign: TextAlign.center),
          ],
        ),
      );
    }
    

    【讨论】:

    • 这就是它现在在已经存在的实现中大致工作的方式:) 唯一的区别是子级只是扩展而不是宽度的 0.3 以更好地适应父级约束。但结果是一样的——列宽不等于图像宽度,这是正确对齐的目标
    • 所以你不希望这 3 张图片之间有任何空格?
    • 我想要的空间取决于图像的大小,而不是屏幕的大小。例如,如果屏幕宽度为 500 px,图像宽度为 100,那么我想要 50px-image-50px-image-50px-image-50px 布局。如果图像是 150,那么我想要12.5px-image-12.5px-image-12.5px-image-12.5px。如果图像是 50,那么我想要87.5px-image-87.5px-image-87.5px-image-87.5px。所以空间的可用空间是screen.width - image.width * images.count。它应该由图像的宽度动态计算,它可以是任意的。
    • 我添加了 3 张截图。在这些图像中,您可以看到空间取决于图像的大小。 3 张截图有 3 张不同尺寸的不同图像。
    • 它们只是按比例缩小以适应SizedBox 的固定宽度size.width * 0.3,我理解正确吗?
    【解决方案4】:

    您可以像这样将Columns 包裹在固定宽度的SizedBoxs 中..

    SizedBox(
            width: 200,
            child: Column(
              children: [
                Image.asset(item.depiction),
                Text(
                  'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et',
                ),
              ],
            ),
          )
    

    【讨论】:

    • 我正在寻找一种没有硬编码值的自适应解决方案(因此它适用于图像的宽度),你能提供这样的解决方案吗?
    • 如果不是硬编码宽度,我们也可以使用屏幕宽度的某个百分比,例如MediaQuery.of(context).size.width * 0.2
    • 在这种情况下重用很复杂,好像这样的小部件有两个用例,第一个比第二个有更多空间,硬编码系数值必须从父级传递也应该手动选择,不是吗?
    • 哦,好吧,你的意思是自适应图像的宽度。我认为自适应屏幕宽度。屏幕宽度百分比的方式只适应屏幕的宽度,是的。不是图片的宽度。
    • 是的,我附上图片链接只是为了澄清这一点,因为从描述中看起来确实不是那么清楚
    猜你喜欢
    • 2017-11-07
    • 1970-01-01
    • 2013-05-14
    • 1970-01-01
    • 2019-04-19
    • 2014-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多