聆听Flutter中的定向状态;旋转前后

时间:2020-08-18 11:32:02

标签: ios flutter dart

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

在入职培训之前,有没有办法采取行动?我不是要抢先轮换,而是要同时进行更改,而不是在此之后进行更改。

目标:

  1. 设备已旋转。
  2. 检测到此并重建UI以显示覆盖。
  3. Flutter执行自己的转换,将用户界面旋转到新的方向。
  4. 在固定时间段后,只需重建即可隐藏叠加层。

挑战,如何在3出现之前实现点2?

3 个答案:

答案 0 :(得分:8)

是的,您可以使用WidgetsBindingObserver通过覆盖didChangeMetrics更早获得方向更改。

如何使用didChangeMetrics

您可以简单地在有状态的小部件的State implementation中混入WidgetBindingObserver

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。


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

答案 1 :(得分:4)

正如您在此链接中看到的那样,没有“自然”的方式来做您想要的事情:
https://github.com/flutter/flutter/issues/16322

尝试使用以下方法制作东西:

  1. 锁定方向:https://dev.to/mightytechno/how-to-change-screen-orientation-in-flutter-32c1
  2. 使用此软件包收听设备旋转更改(因为方向不会更改):https://pub.dev/packages/native_device_orientation
  3. 进行自定义
  4. 使用第1步中的链接设置新方向

您可以尝试使用动画容器以获得更好的效果,但是在设置新方向之前,您需要手动处理所有屏幕位置和旋转:
https://api.flutter.dev/flutter/widgets/AnimatedContainer-class.html

答案 2 :(得分:0)

您可能想尝试的事情是编写一个平台通道方法,以从加速度计获取传感器数据,然后将其提供给Transform.rotate()之类的东西。