flutter疑难杂症之记一次RenderBox测量坐标错误
项目中用到精确坐标计算,要求在绘制完成后立即测量控件在屏幕中的坐标,代码如下:
void initState(){
...
WidgetsBinding.instance.addPostFrameCallback((callback) {
_calculateAfterLayout();
});
...
}
///求取绘制成功的时候的x和y坐标的位置
void _calculateAfterLayout() {
RenderBox screenObject = _screenKey.currentContext.findRenderObject();
final screenPosition = screenObject.localToGlobal(Offset.zero);
_curX = screenPosition.dx;
_curY = screenPosition.dy;
}
代码正常情况下没有问题,但是出问题的时候是initstate中请求数据比较缓慢,然后导致计算的结果有偏差,并且在IOS和Android不同的平台上偏差还不一样,在IOS表现为dx偏差,在Android表现为dy偏差,具体如下图:
绿色的边界图形为计算而来的坐标展示的位置,它应该在中间屏幕左上角才是正常的,但是现在,这个图形在IOS表现为靠右,在Android表现为靠下。
(由于gif图不清楚,上传一张没有压缩的图片)
为什么会出现这样的情况呢,经过仔细观察可以知道,IOS的页面切换是从右往左切换,而Android的页面切换是从下往上,那么我有一个猜想,它们会不会是在切换的过程中被计算了坐标,如下:
如果是按照以上的猜想,那么就会出现测量不准确的现象。为了验证我的猜想,特将flutter中的material切换换成了自定义的切换,代码如下:
Navigator.of(context).pushAndRemoveUntil(
PageRouteBuilder(pageBuilder: (BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation) {
// 跳转的路由对象
return ScreenPage();
}, transitionsBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) {
return SlideTransition(
position: new Tween<Offset>(
begin: const Offset(0.0, 0.0),
end: Offset.zero,
).animate(animation),
child: new SlideTransition(
position: new Tween<Offset>(
begin: Offset.zero,
end: const Offset(0.0, 0.0),
).animate(secondaryAnimation),
child: child,
),
);
}),
(route) => route == null);
果然,将路由切换改成非滑动模式,这个bug就没有出现了,如下:
还有一个问题,当第一次测量不准确的时候,对屏幕放大进行测量的坐标是准确的,然后再次缩小到第一次进入的时候的大小,测量坐标又不准确了,并且测量误差和第一次一样,说明对于已经测量过的初始值,Flutter不会再次测量,而是直接赋值。
虽然问题解决了,但是这种方式只能规避,至于为啥Flutter中会在页面切换过程中而不是切换完成后再计算坐标,调用WidgetsBinding.instance.addPostFrameCallback监听绘制事件完成后才进行计算仍然有误,恐怕这也是Flutter留给我们的坑了。
flutter很好,路还很长,让我们一起奋斗前行!