根据另一个小部件的位置/大小定位/调整小部件的位置/大小

14

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

以下是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>

  • 父元素占据整个宽度(不重要)。
  • 父元素高度为最高子元素的高度。
  • 高度较小的子元素会被拉伸以适应父元素。
  • 子元素紧邻着彼此定位。

在Flutter中,我认为我们无法同时拥有以上所有4个特点。

现在如果我们有两个包含这种布局的列表,并且有一个动画,其中一个元素从一个列表移到另一个列表,会怎样呢? 例如:

enter image description here enter image description here

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

enter image description here

这些都是完全随机的示例。 我不需要复制相同的东西。 真正的问题是:是否有一种通用方法可以进行类似的操作(获取屏幕大小/位置)? 这种方法将不会针对此用例而是易于维护吗?

1个回答

17
为了回答你最初的布局问题,你可以使用IntrinsicHeight小部件和CrossAxisAlignment.stretch来实现这种布局。它看起来像这样:screenshot这是代码:
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来定位方块。请参阅画廊中使用此类进行高级动画的动画演示的示例:

screenshot


啊,太酷了,我不知道你可以这样使用 IntrinsicHeight。另一方面,对于我展示的动画,CustomChildLayout 不起作用。不仅 CustomChildLayout 的大小不能依赖于子元素;而且它仍然无法解决访问全局小部件的世界位置/大小的问题。 - Rémi Rousselet
你提出了很多问题,我认为你应该考虑将它们拆分成自己的Stack Overflow问题。如果你正在使用MultiChildLayoutDelegate,则在performLayout中会向你提供widget的大小。您可以通过调用layoutChild来确定子项的大小。如果您想获取renderObject的全局坐标,则可以使用localToGlobal,尽管如果您这样做,您可能会违反封装性,并且应该在更高级别上实现自定义布局。 - Collin Jackson
请注意,对于简单的用例,您可以使用 LayoutBuilder 来获取包围小部件的大小约束。如果您正在实现 MultiChildLayoutDelegate,则不需要使用它。 - Collin Jackson
谢谢,但就像我说的,MultiChildLayout(又名CustomChildlayout)不起作用。虽然您可以在performLayout中获取子级大小,但您将无法在getSize内访问其大小。 - Rémi Rousselet
这确实违反了封装性原则。但对于某些动画,例如像英雄一样的动画,没有其他解决方案。假设您想在Scaffold正文中将图像视觉化为Scaffold AppBar中的购物车图标,则别无选择。 - Rémi Rousselet
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接