Flutter:获取Matrix4 Transform变换后的容器宽高
Flutter中获取Transform 3D旋转后容器的实际屏幕高度
当使用Transform结合Matrix4进行3D旋转时,RenderBox.size返回的是布局阶段的原始尺寸——因为Transform仅在绘制阶段对组件进行变换,不会改变布局计算的结果。要获取旋转后容器在屏幕上的实际高度,有两种可靠的方法:
方法一:通过旋转角度直接计算(正交变换场景)
如果你的变换是正交旋转(未添加透视效果,即未设置Matrix4的透视参数),可以利用三角函数直接推导变换后的高度。以绕X轴旋转为例,旋转角度为θ时,屏幕上的投影高度等于原始高度乘以cos(θ)。
代码示例
修改你的尺寸获取函数:
void getSize(GlobalKey key) { WidgetsBinding.instance.addPostFrameCallback((_) { // 获取当前旋转角度 double rotationAngle = _controller.value * 2 * pi / 8; RenderBox renderBox = key.currentContext?.findRenderObject() as RenderBox; double originalHeight = renderBox.size.height; // 计算变换后的高度 double transformedHeight = originalHeight * cos(rotationAngle); print('原始高度: ${renderBox.size.height}'); print('变换后的高度: $transformedHeight'); }); }
方法二:通过顶点坐标计算(通用场景)
如果你的变换包含透视效果,或者旋转中心不是组件中心,直接计算会有误差。此时可以通过获取容器四个顶点的屏幕坐标,计算Y轴方向的极值差来得到实际高度。
代码示例
实现一个通用的变换后尺寸获取函数:
void getTransformedSize(GlobalKey key) { WidgetsBinding.instance.addPostFrameCallback((_) { final renderBox = key.currentContext?.findRenderObject() as RenderBox; // 获取从容器到屏幕的变换矩阵 final transform = renderBox.getTransformTo(null); // 容器的四个局部顶点坐标 final topLeft = Offset(0, 0); final topRight = Offset(renderBox.size.width, 0); final bottomLeft = Offset(0, renderBox.size.height); final bottomRight = Offset(renderBox.size.width, renderBox.size.height); // 将局部坐标转换为屏幕坐标 final screenPoints = [ transform.transform(topLeft), transform.transform(topRight), transform.transform(bottomLeft), transform.transform(bottomRight), ]; // 计算Y轴的最大最小值,差值即为实际高度 final yValues = screenPoints.map((p) => p.dy).toList(); final minY = yValues.reduce(min); final maxY = yValues.reduce(max); final transformedHeight = maxY - minY; print('原始高度: ${renderBox.size.height}'); print('变换后的实际高度: $transformedHeight'); }); }
代码优化提示
不要在AnimatedBuilder的builder方法中重复添加状态监听器,这会导致多次注册。将监听器移到initState中:
@override void initState() { super.initState(); _controller = AnimationController( duration: const Duration(seconds: 2), vsync: this, ); // 只注册一次状态监听器 _controller.addStatusListener((status) { if (status == AnimationStatus.completed) { getTransformedSize(containerKey); } }); }
内容的提问来源于stack exchange,提问作者Zakaria Louizy
相关产品推荐
相关产品推荐

