【问题标题】:Listen to Orientation State in Flutter; before & after rotation在 Flutter 中监听方向状态;旋转前后
【发布时间】:2020-12-07 14:03:30
【问题描述】:

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

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

目标:

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

挑战,如何在第3点出现之前完成第2点?

【问题讨论】:

  • 不,这是不可行的。你想做什么?
  • 我想在屏幕变换/旋转时在屏幕上盖上一层面纱,因为它看起来很糟糕。想象一下,当您在 iPadOS 上调整应用程序的大小时,它会在重新缩放时模糊内容。简单的效果,但如果不能在转换的同时应用它(而不是之后),不知道如何实现它。
  • 尝试使用 MediaQuery,但不确定它是否可以工作。
  • 我认为这达到了同样的问题。在方向改变之前无法获取该信息并重建。
  • @RémiRousselet 您如何确定这是不可行的?

标签: ios flutter dart


【解决方案1】:

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

如何使用didChangeMetrics

您可以简单地将WidgetBindingObserver 混合到有状态小部件的State implementation 中:

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。


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

【讨论】:

  • 非常感谢您在此处的详细细分,但是尽管在轮换开始时进行了注册,但直到轮换完成后,重建才会真正发生/完成。例如。为您的Container 添加颜色。在didChangeMetricssetState 中更改一个布尔值isRotating = true。为了测试起见,我只是在 1-2 秒后用 Timer 将其设置回 false。使用 bool 更改颜色,但直到旋转后颜色才会改变。
  • @JoshKahane 是的,没错 :) 这是因为构建将与OrientationBuilder 同时发生。那时候看来你根本就不会画画(:
  • 这对我的任务真的很有帮助。非常感谢!
【解决方案2】:

正如您在此链接中看到的那样,没有“自然”的方式来做您想做的事:
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

【讨论】:

    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 2021-02-17
      • 1970-01-01
      • 2020-03-26
      • 2022-10-14
      • 2022-10-23
      • 2020-03-27
      • 2012-03-15
      • 2021-03-06
      • 1970-01-01
      相关资源
      最近更新 更多