OrientationBuilder
在全面的转换完成后才报告方向更改,然后重建发生在此之后。
有没有一种方法在方向启动之前就开始操作? 我不是要预先旋转,而是同时进行更改,而不是在之后。
目标:
- 设备已旋转。
- 检测到并重新构建UI以显示覆盖层。
- Flutter执行自己的转换,将UI旋转到新方向。
- 经过一段固定的时间后,简单地重建以隐藏覆盖层。
挑战在于如何在第三步发生之前实现第2点?
OrientationBuilder
在全面的转换完成后才报告方向更改,然后重建发生在此之后。
有没有一种方法在方向启动之前就开始操作? 我不是要预先旋转,而是同时进行更改,而不是在之后。
目标:
挑战在于如何在第三步发生之前实现第2点?
您可以通过覆盖 didChangeMetrics
,使用 WidgetsBindingObserver
来提前获取屏幕方向变更。
didChangeMetrics
您只需将 WidgetBindingObserver
混入有状态组件的 State
实现中即可:
class _FooState extends State with WidgetsBindingObserver {
@override
void didChangeMetrics() {
// This will be triggered by changes in orientation.
}
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
}
方向由可用尺寸的宽高比决定。这意味着你可以使用以下代码在didChangeMetrics
中获取方向:
final orientation = WidgetsBinding.instance.window.physicalSize
.aspectRatio > 1 ? Orientation.landscape : Orientation.portrait;
我构建了一个示例 StatefulWidget
,将 OrientationBuilder
回调与 didChangeMetrics
进行比较:
import 'package:flutter/material.dart';
void main() {
runApp(OrientationListener());
}
class OrientationListener extends StatefulWidget {
@override
_OrientationListenerState createState() => _OrientationListenerState();
}
class _OrientationListenerState extends State<OrientationListener>
with WidgetsBindingObserver {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
void didChangeMetrics() {
print('$WidgetsBindingObserver metrics changed ${DateTime.now()}: '
'${WidgetsBinding.instance.window.physicalSize.aspectRatio > 1 ? Orientation.landscape : Orientation.portrait}');
}
@override
Widget build(BuildContext context) {
return MediaQuery(
data: MediaQueryData.fromWindow(WidgetsBinding.instance.window),
child: OrientationBuilder(
builder: (context, orientation) {
print('$OrientationBuilder rebuild ${DateTime.now()}: $orientation');
return Container();
},
),
);
}
}
运行此示例会显示两个函数的以下时间:
WidgetsBindingObserver metrics changed 2020-08-22 14:47:01.690172: Orientation.portrait
WidgetsBindingObserver metrics changed 2020-08-22 14:47:01.706574: Orientation.landscape
OrientationBuilder rebuild 2020-08-22 14:47:01.760589: Orientation.landscape
WidgetsBindingObserver metrics changed 2020-08-22 14:47:06.537083: Orientation.landscape
WidgetsBindingObserver metrics changed 2020-08-22 14:47:06.549545: Orientation.portrait
OrientationBuilder rebuild 2020-08-22 14:47:06.603859: Orientation.portrait
WidgetsBindingObserver metrics changed 2020-08-22 14:47:10.423787: Orientation.portrait
WidgetsBindingObserver metrics changed 2020-08-22 14:47:10.442866: Orientation.landscape
OrientationBuilder rebuild 2020-08-22 14:47:10.501729: Orientation.landscape
WidgetsBindingObserver metrics changed 2020-08-22 14:47:13.639545: Orientation.landscape
WidgetsBindingObserver metrics changed 2020-08-22 14:47:13.658906: Orientation.landscape
WidgetsBindingObserver metrics changed 2020-08-22 14:47:13.672025: Orientation.portrait
OrientationBuilder rebuild 2020-08-22 14:47:13.730771: Orientation.portrait
针对我的情况,检测差异约为0.06
秒。
从上面可以看出来,这个差异是微不足道的(我认为)。所以我甚至不确定这是否对你有用。
此外,我观察到在设备旋转开始时实际上会调用OrientationBuilder
回调 - 至少在我的 Android 模拟器上是如此。这意味着您可以在旋转发生之前重新构建您的 UI。
希望这对您有所帮助 :)
didChangeMetrics
中,使用setState
更改布尔值isRotating = true
。为了测试,我只需在1-2秒后使用Timer
将其设置回false。使用布尔值更改颜色,但颜色直到旋转后才会更改。 - Josh KahaneOrientationBuilder
同时发生。看起来你可以在那个时候不进行绘制 (: - creativecreatorormaybenot你可能想尝试的一件事是编写一个平台通道方法来获取加速度计的传感器数据,然后将其提供给类似 Transform.rotate() 的函数进行处理。