如何检测 Flutter 中布局的方向变化?

Posted

技术标签:

【中文标题】如何检测 Flutter 中布局的方向变化?【英文标题】:How to detect orientation change in layout in Flutter? 【发布时间】:2018-11-21 17:22:59 【问题描述】:

如何在 Flutter 中判断方向是纵向还是横向

if(portrait)
  return ListView.builder()
else
  return GridView.count()

【问题讨论】:

【参考方案1】:

为了确定屏幕的方向,我们可以使用OrientationBuilder Widget。 OrientationBuilder 将确定当前的 Orientation 并在 Orientation 更改时重建。

new OrientationBuilder(
  builder: (context, orientation) 
    return new GridView.count(
      // Create a grid with 2 columns in portrait mode, or 3 columns in
      // landscape mode.
      crossAxisCount: orientation == Orientation.portrait ? 2 : 3,
    );
  ,
);

您可以在此处找到完整的示例: https://flutter.io/cookbook/design/orientation/

【讨论】:

我在 android 上使用过它,当设备的自动旋转启用时它工作正常,但大多数人使用他们的手机禁用自动旋转(强制纵向)并且 OrientationBuilder 不会触发景观。无论如何我们可以检测到关于自动旋转状态的方向吗? 你觉得github.com/flutter/flutter/issues/19259怎么样? 此选项的缺点是您可以区分方向,例如 LandscapeLeft 和 LandscapeRight。【参考方案2】:

您可以使用MediaQuery 来检查方向:

var isPortrait = MediaQuery.of(context).orientation == Orientation.portrait

【讨论】:

@AdarshVijayanP 您不能在随机代码位置使用它。应该用在builddidChangeDependencies @GünterZöchbauer 在build 中编写代码,然后传递给我的小部件,谢谢,现在效果很好。【参考方案3】:

很简单

if (MediaQuery.of(context).orientation == Orientation.portrait)
    // is portrait
else
// is landscape

【讨论】:

【参考方案4】:
@override
Widget build(BuildContext context) 
  return Scaffold(
    body: OrientationBuilder(builder: (_, orientation) 
      if (orientation == Orientation.portrait)
        return _buildPortraitLayout(); // if orientation is portrait, show your portrait layout
      else
        return _buildLandscapeLayout(); // else show the landscape one
    ),
  );

【讨论】:

OrientationBuilder 似乎只适用于脚手架级别的构建。当我构建一个有状态的小部件时,它似乎并没有在树的下方工作。我想知道这是否是已知的事情。【参考方案5】:
OrientationBuilder(


 builder: (context, orientation) 
      return orientation == Orientation.portrait
          ? SafeArea(
          child: Scaffold(
              body: PortraitMode(context)
          )
      )
          : LandscapeMode(context);

    
);

【讨论】:

【参考方案6】:

为了完整起见,我想添加另一种在 Flutter 中检测方向的方法。答案中已经提到了两种检测方法。他们是

    媒体查询 方向生成器

当我从 Google 工程师的响应式设计video(跳到第 2:34 分钟)学习 Flutter 时,我遇到了第三种方法。它被称为Layout Builder。这是简短的sn-p:

return Padding(
    padding: _padding,
    child: LayoutBuilder(
        builder: (BuildContext context, BoxConstraints constraints) 
            if(constraints.maxHeight > constraints.maxWidth) 
                return _getPortraitLayout();
            
            else 
                return _getLandscapeLayout();
            
        ,
    ),
);

【讨论】:

这仅适用于您在不受约束的布局中使用 Layout Builder(例如,在屏幕小部件树的顶部)。如果你将 LayoutBuilder 放在一个高度为 50 且宽度为 100 的容器中,你的方法将始终告诉用户他处于横向模式【参考方案7】:

Mediaquery 不能在initState() 中使用,并且 OrientationBuilder 需要一个小部件,所以我创建了以下可以在项目中的任何地方使用的类。

if(IsPortrait.isPortrait)
else

IsPortrait.class

class IsPortrait
  static bool isPortrait = true;

  void init(BoxConstraints constraints, Orientation orientation) 
    if (orientation == Orientation.portrait) 
      isPortrait = true;
    
   else
     isPortrait = false;
   
  

以下功能可用于改变方向

仅纵向模式

/// blocks rotation; sets orientation to: portrait
void _portraitModeOnly() 
  SystemChrome.setPreferredOrientations([
    DeviceOrientation.portraitUp,
    DeviceOrientation.portraitDown,
  ]);

仅限横向模式

/// blocks rotation; sets orientation to: landscape
    void _landscapeModeOnly() 
      SystemChrome.setPreferredOrientations([
    DeviceOrientation.landscapeLeft,
    DeviceOrientation.landscapeRight,
      ]);
    

启用纵向和横向

void _enableRotation() 
  SystemChrome.setPreferredOrientations([
    DeviceOrientation.portraitUp,
    DeviceOrientation.portraitDown,
    DeviceOrientation.landscapeLeft,
    DeviceOrientation.landscapeRight,
  ]);

【讨论】:

【参考方案8】:

我的变种。

1) 在全局范围内设置全局 ValueNotifier:

final ValueNotifier<bool> IS_PORTRAIT = ValueNotifier<bool>(true);

2) 在我们的全局 ValueNotifier 的脚手架范围内更改值

return Scaffold(
        key: scaffoldKey,
        body: OrientationBuilder(
          builder: (BuildContext context, Orientation orientation) 
            IS_PORTRAIT.value = orientation == Orientation.portrait;
            return MyBody();
          ,
        ),
);

3) 听当前方向的任何地方

return ValueListenableBuilder(
                  valueListenable: IS_PORTRAIT,
                  builder: (BuildContext context, value, Widget child) 
                     return Container(
                      color: Colors.green[100],
                      child: Container(),
                      height: (IS_PORTRAIT.value)? 150: 80,
                    );
                  ,
                );

【讨论】:

以上是关于如何检测 Flutter 中布局的方向变化?的主要内容,如果未能解决你的问题,请参考以下文章

Flutter 如何听设备暗色主题瞬间变化

如何在 Flutter 中检测设备运动方向?

Flutter:找不到方向性小部件

Flutter - 无法检测/识别 Android Studio

如何使用 Flutter 与 ERC721 智能合约交互?

检测屏幕方向变化(快速)