在 Flutter 中监听方向状态;旋转前后

Jos*_*ane 11 ios dart flutter

OrientationBuilder 在完全转换发生后报告方向变化,然后重建发生在此之后。

有没有办法在定向开始之前采取行动?我不是要抢先轮换,而是同时进行更改,而不是之后。

目标:

  1. 设备旋转。
  2. 检测到这一点并重建 UI 以显示叠加层。
  3. Flutter 执行自己的转换,将 UI 旋转到新的方向。
  4. 在固定时间段后,只需重建以隐藏叠加层。

挑战,如何在第 3 点发生之前完成第 2 点?

cre*_*not 12

是的,你可以得到的方位变化更早使用WidgetsBindingObserver通过重写didChangeMetrics

如何使用 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();
  }
}
Run Code Online (Sandbox Code Playgroud)

确定方向

方向由可用尺寸的纵横比决定。这意味着您可以didChangeMetrics使用以下代码获得方向:

final orientation = WidgetsBinding.instance.window.physicalSize
    .aspectRatio > 1 ? Orientation.landscape : Orientation.portrait;
Run Code Online (Sandbox Code Playgroud)

例子

我构建了一个示例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();
        },
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

结果

运行此示例显示两个函数的以下时间:

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
Run Code Online (Sandbox Code Playgroud)

所以在我的情况下,检测的差异大约是0.06几秒钟。

观察

从上面可以看出,差异是微不足道的(我会说)。所以我什至不确定这对你是否有用。

此外,我观察到OrientationBuilder回调实际上是在设备旋转开始时调用——至少在我的 Android 模拟器上是这样。这意味着您可以在旋转发生之前重建您的 UI。


我希望这对你有所帮助:)