【问题标题】:Positioning/Sizing a widget depending of the position/size of another widget根据另一个小部件的位置/大小定位/调整小部件的大小
【发布时间】:2018-02-10 00:35:55
【问题描述】:

我曾经在 Flutter 中遇到过几次已经相当大的墙。 动画或构建小部件,这取决于其他小部件来获取它们的大小/位置。

一些可能是我最糟糕的噩梦的例子: 动态地将小部件彼此相邻。 在 css 中我们会有这个:

.root {
    display: flex;
    background: grey;
    padding: 4px;
}
.root > div {
  background: lightgrey;
  margin-right: 5px;
  padding: 5px;
}
<div class="root">
    <div>
         dynamic height
         <br/>
         dynamic width
         <br/>
         fat
         <br/>
         super fat
    </div>
    <div>
         dynamic width
         <br/>
         dynamic height
    </div>
</div>
  • 父级占据全宽(不重要)。
  • 父母采用最大孩子的身高。
  • 身高较小的孩子适合父母
  • 孩子们紧挨着放置

在颤振中,我认为我们不能同时获得所有 4 个点。

现在,如果我们有 2 个这个列表和一个动画,其中一个元素从一个列表移动到另一个列表,该怎么办? 例子

另一个例子。如果我们想让SlideTransition 与另一个没有共同点的小部件垂直对齐怎么办? 像这样:

这些都是完全随机的例子。我不需要复制同样的东西。 这里真正的问题是:是否有一种 generic 方法可以做类似的事情(获取屏幕尺寸/位置)? 不是特定于该用例并且以后易于维护的东西?

【问题讨论】:

    标签: flutter dart flutter-layout flutter-animation flutter-widget


    【解决方案1】:

    要回答您最初的布局问题,您可以使用IntrinsicHeight 小部件和CrossAxisAlignment.stretch 完成此布局。它看起来像这样:

    代码如下:

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(new MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return new MaterialApp(
          home: new MyHomePage(),
        );
      }
    }
    
    class MyHomePage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return new Scaffold(
          body: new Padding(
            padding: new EdgeInsets.all(10.0),
            child: new IntrinsicHeight(
              child: new Container(
                color: Colors.grey,
                padding: new EdgeInsets.all(4.0),
                child: new Row(
                  mainAxisAlignment: MainAxisAlignment.start,
                  crossAxisAlignment: CrossAxisAlignment.stretch,
                  children: <Widget>[
                    new Container(
                      padding: new EdgeInsets.all(5.0),
                      margin: new EdgeInsets.only(right: 5.0),
                      color: Colors.grey[200],
                      child: new Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: <Widget>[
                          new Text('dynamic height'),
                          new Text('dynamic width'),
                          new Text('fat'),
                          new Text('super fat'),
                        ],
                      ),
                    ),
                    new Container(
                      padding: new EdgeInsets.all(5.0),
                      color: Colors.grey[200],
                      child: new Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: <Widget>[
                          new Text('dynamic width'),
                          new Text('dynamic height'),
                        ],
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ),
        );
      }
    }
    

    要实现更高级的动画示例,我建议使用CustomMultiChildLayout 来定位框。有关使用此类的高级动画示例,请参阅 Gallery 的 animation demo

    【讨论】:

    • 啊酷,不知道你可以这样使用IntrinsicHeight。另一方面,对于我展示的动画,CustomChildLayout 将不起作用。不仅 CustomChildLayout 的大小不能依赖于 children ;但它仍然不能解决访问全局小部件的世界位置/大小的问题。
    • 您问了很多问题,我认为您应该考虑将它们拆分为他们自己的 Stack Overflow 问题。如果您使用MultiChildLayoutDelegate,则您的小部件的大小将在performLayout 中提供给您。您可以致电layoutChild 确定您孩子的大小。如果你想获得renderObject 的全局坐标,你可以使用localToGlobal,但如果你这样做,你可能违反了封装,应该在更高级别实现自定义布局
    • 请注意,对于简单的用例,您可以使用LayoutBuilder 来获取围绕小部件的大小限制。不过,如果您正在实施 MultiChildLayoutDelegate,则不需要这个。
    • 谢谢,但就像我说的那样,MultiChildLayout(又名 CustomChildlayout)不起作用。虽然您可以在 performLayout 中获取儿童尺寸,但您将无法在 getSize 中访问它们的尺寸。
    • 违反封装的。但是对于一些动画没有其他的解决方案,比如Hero之类的。假设您想将 Scaffold 主体内的图像直观地转换为 Scaffold AppBar 内的购物车图标。你别无选择。
    【解决方案2】:
    • 父母取最大孩子的身高

    您可以在行或列中使用 MainAxisSize.min,它可以作为父小部件的包装。

    body: new Container(
    
     color: Colors.yellowAccent,
    
     child: new Row(
    
     mainAxisSize: MainAxisSize.min,
    
     children: [...],
    
     ),
    
    )
    
    • 身高较小的孩子可以伸展以适应父母

    FractionallySizedBox 是一个小部件(一个容器),根据它的 widthFactor 和 heightFactor,将设置所有子小部件。您可以将其视为一种比例值。因此,如果我们想拥有一个水平和垂直占用一半可用空间的容器,我们将执行以下操作:

    @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text("FractionallySizedBox"),
          ),
          body: FractionallySizedBox(
            widthFactor: 0.5,
            heightFactor: 0.5,
            child: Container(
              // this container won't be larger than
              // half of its parent size
            ),
          ),
        );
      }
    
    • 孩子们紧挨着放置

    当您想要将子项放置在彼此旁边时,每个颤动布局都使用行和列。

    Row(
        children: [
              YourWidget(),
              YourWidget(),
              YourWidget(),
          ]
     )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-09-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多