1

FlutterComponent最佳实践之Widget尺寸

 1 year ago
source link: https://blog.csdn.net/eclipsexys/article/details/129700802
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

44f3871a9cf517473d714af7a7f78f86.png

点击上方蓝字关注我,知识会给你力量

55991827350b2bc28ae13b687b6444ae.png

Flutter和在Native中,对一个Widget的尺寸测量,一直都是一个非常麻烦的事情,大部分时间,我们都是按照约束和具体的尺寸来进行布局,但有些时候,我们不得不拿到动态的Widget尺寸来实现自己的一些布局策略。通常来说,我们会有三方面的需求。

  • 测量自己的尺寸

  • 测量Parent的尺寸

  • 测量Child的尺寸

测量自己的尺寸

要获取你自身的Widget尺寸,其实只需要通过RenderBox即可获取。

不过要注意的是,findRenderObject不能写在build方法中,因为这个时候,renderobject还未挂载。

测量Parent尺寸

对于Parent来说,我们可以通过LayoutBuilder来快速获得它的约束范围,从而获取Parent的尺寸,代码如下。

这是一个很方便的功能,因为你可以根据当前宽度和比例来调整当前Widget的尺寸,从而更加符合约束的视觉限制。

测量Child尺寸

测量Child的尺寸要比上面两种要复杂一点,我们一般还是会通过findRenderObject来获取尺寸信息,然后将其通过回调传递给当前Widget。



newCodeMoreWhite.png

我们创建一个MeasurableWidget,用来测量Child的尺寸,并传入回调来获取尺寸,使用代码如下。

这个方法其实遇到了和「测量自身」一样的问题,那就是build的时候,RenderObject未挂载,所以这里需要Render两次才能获取最终的尺寸,这样其实并不是很优雅,虽然大部分时候,局部Context的刷新并不太耗性能,但是还是应该尽可能的减少刷新的次数。

那么获取Child的尺寸有什么用呢?通过获取Child的尺寸,我们可以根据尺寸来做一些偏移,例如下面的示例。

那么我们是否有办法来避免这个「两次刷新」呢?答案是肯定的,我们不能一次性获取尺寸的原因,实际上就是RenderObject没挂载好,所以,我们可以自定义一个RenderObject,给它设置回调来获取尺寸。

首先,我们先定义一个RenderProxyBox,并不需要修改什么逻辑,只要在其performLayout方法中,通过WidgetsBinding.instance.addPostFrameCallback来增加一个回调监听即可。



newCodeMoreWhite.png

接下来,再定义一个SingleChildRenderObjectWidget来承载它即可。

使用也很简单,使用MeasurableWidget包裹下就好了。

是不是有点意思,其核心原理还是通过WidgetsBinding.instance.addPostFrameCallback来获取尺寸回调的时机,但是封装了一层,就优雅了很多。

前面我们是通过自定义RenderProxyBox来处理addPostFrameCallback调用的时机问题,那么除了这种方式以为,还可以通过mixin来处理这个问题,代码如下所示。



newCodeMoreWhite.png

那么有了这个mixin之后,就可以很方便的封装一个Widget,来创建类似前面的回调。



newCodeMoreWhite.png

这样我们就可以很方便的使用它了。

可以发现,其实我们解决问题的方法有很多,但殊途同归,有很多时候,我们都可以从不同角度去解决同一个问题,这样对我们不仅仅是技术的提高,也是认知的提高。

通过Key

前面我们在获取尺寸的时候,要么是在Build之后通过context获取,要么就是创建Custom RenderObject来增加监听,这些方法的本质,实际上都是通过WidgetsBinding.instance.addPostFrameCallback获取刷新时机,再通过findRenderObject来获取尺寸,所以,借助Key,我们可以在不自定义Custom RenderObject的前提下,获取尺寸的一般方法。

要注意的是,未渲染的Widget,通过GlobalKey获取的currentContext为null。



newCodeMoreWhite.png

前两种方式,无非是通过GlobalKey来获取BuildContext和RenderBox,其本质是一样的。但是这些方法都只限制于获取Box模型中的尺寸,如果在Sliver结构中国,则只能通过其内部的容器Widget来间接获取其尺寸。

Size Notifications

在Flutter中,Notifications是向上冒泡的,如果你需要某些尺寸,并在多个层级的Widget上传递,Notifications就是一个最好的选择,你需要做的只是定义一些自定义Notifications。

首先,我们创建一个Notifications。

然后在获取到尺寸的地方通过dispatch将size分发出来,在需要监听的地方,使用NotificationListener来做监听即可。

这样就可以将Size在Widget Tree上传递了。这样的好处就是Widget和监听者之间没有太多的耦合,即使跨越多个层级,你依然可以获取这些通知,它的使用场景很多,例如在一些菜单动画中,你需要在MenuController和被选中的MenuButtons之间获取这种尺寸的处理。

MediaQuery.of(context)

MediaQuery.of(context)是我们经常访问的一个代码,用来获取到设备相关的一些尺寸信息,但是它的调用稍微复杂一点,比如。

MediaQuery.of(context).size.height

类似的还有很多,所以我们可以借助Dart的extension来对BuildContext进行拓展。



newCodeMoreWhite.png

这样在使用的时候,可以直接通过context来引用。

要注意的是,MediaQuery.of(context).size.height在release mode下第一次获取的值可能是0,所以需要对这种情况进行下处理,避免出现0/0的问题。

向大家推荐下我的网站 https://www.yuque.com/xuyisheng  点击原文一键直达

专注 Android-Kotlin-Flutter 欢迎大家访问

本文原创公众号:群英传,授权转载请联系微信(Tomcat_xu),授权后,请在原创发表24小时后转载。

< END >

作者:徐宜生

更文不易,点个“三连”支持一下👇


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK