Flutter-获取子组件尺寸的历程

1,536 阅读3分钟

背景

上周,小E接到了一个需求,下面是需求描述: 因为现在的手机屏幕比例不一致,界面上需要根据剩下的高度决定显示不同的组件,这里小E将高度最大的组件记为 L,高度中等的组件记为 M,高度最小的组件记为 S。

开始

小E刚开始接到这个需求的时候,想得比较简单,使用 LayoutBuilder 组件获取父组件的约束就可以知道剩下的高度是多少了,然后,L、M、S三个组件的高度都是固定的,直接拿他们的高度写个 if 就搞定了。

转折

组长看了小E的代码,找小E谈话:“这个地方直接用固定数值来判断不太合适,如果以后这几个组件要修改,这个地方就需要跟着修改,所以能不能通过计算子组件的高度,然后再判断显示哪个组件?“,小E:“好的,我这就改。”。

实现

小E在 《Flutter实战·第二版》中发现了AfterLayout组件,这是作者自己封装的,书中也有贴出源码。这个组件的作用是调用者可以通过传入回调函数的方式获得组件的 RenderBox,从 performLayout 的代码来看,组件本身的尺寸跟子组件一致,所以可以获得子组件的尺寸。实现的关键是在回调函数里拿到子组件的高度,然后跟父组件约束的高度做比较

意料之外的事

本来以为会有“闪烁”的情况,因为回调函数是在下一帧才调用的,但是并没有出现,可能是子组件不复杂,看不出来“闪烁”。如果出现的话可以通过使用 Visibility 组件,将一开始的状态设置为隐藏。希望知道原因的大佬能在评论区告诉小E。

挫折

理论形成之后,小E一鼓作气写完逻辑代码,然后按下启动按钮进行调试,等待结果的过程有点激动,有点紧张,没错,结果并不如小E所想,挫折来了。经过小E的一番打印、断点等操作,发现子组件受到的约束是一个紧约束,所以高度被固定了。小E尝试使用 UnconstrainedBox 组件解除约束,然后传递一个新的松约束给子组件,结果报错了。又一番打印、断点等操作之后,发现子组件受到的约束还是一个紧约束。可能是当时有点乱,小E试过使用 Stack 组件、Column 组件,都没有正确计算出子组件的高度,当天晚上没有解决这个问题,组长说先回去休息吧,明天再弄,小E很感动,于是就先回家了。经过一个晚上的休息之后,海马体趁小E睡着的时间帮小E整理了一些知识点和思路。第二天早上,小E重新整理了代码的结构,最终使用 Wrap 组件解决了约束的问题。小E在写这篇笔记的时候,使用 Align 组件重新调试了代码,也是可以更改约束为松约束。归根究底,还是对布局的不熟悉,看来小E得重新看看张风捷特烈大佬写的《Flutter布局探索-薪火相传》

另一个挫折,L 组件中使用了 Visibility 组件,一开始这个组件的状态为 false,以至于计算得到的子组件高度不是意料之内,印象中这个组件默认是有占位的,于是我没多看一眼。后来组长提醒我看看这个组件的参数,说是可以实现占位效果,我才发现变了,不知道是我记错了,还是 Flutter 改过这个组件。

最后

AfterLayout(
  callback: (RenderAfterLayout renderObj) {
    atFirstLayout(renderObj, ct);
  },
  child: waitingCalcWidget,
)

void atFirstLayout(RenderAfterLayout renderObj, BoxConstraints ct){
  final ch = renderObj.size.height;
  if (ch > ct.maxHeight) {
    setState((){
      ......
    });
  }
}