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

问题描述 投票:0回答:9

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

if(portrait){
  return ListView.builder()
}else{
  return GridView.count()
}
dart orientation flutter flutter-layout
9个回答
114
投票

为了确定屏幕的方向,我们可以使用

OrientationBuilder
小部件。 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/


113
投票

您可以使用

MediaQuery
检查方向:

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

22
投票

这很容易

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

6
投票
@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
    }),
  );
}

3
投票

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

  1. 媒体查询
  2. 方向生成器

还有第三种方法,是我在 Google 工程师的响应式设计视频(跳至 2:34 分钟)学习 Flutter 时遇到的。这就是所谓的

Layout Builder
。这是简短的片段:

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

2
投票
OrientationBuilder(


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

    }
);

1
投票

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,
  ]);
}

1
投票

我的变体。

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,
                    );
                  },
                );

0
投票

只需保存并比较当前方向的值即可。类似于:-

class CheckOrientationSampleState extends State<CheckOrientationSample> {
  
  bool? isCurrentPortrait;
  //Non-Mandatory in case of single use
  bool orientationChange = true;

  bool checkOrientationChange(BuildContext context) {
    bool ret = false;
    bool isPortrait = MediaQuery.of(context).orientation == Orientation.portrait;;

    if (isCurrentPortrait == null) {
      isCurrentPortrait = MediaQuery.of(context).orientation == Orientation.portrait;;
      ret = true;
    } else if (isCurrentPortrait != isPortrait) {
      isCurrentPortrait = isPortrait;
      //Non-Mandatory in case of single use
      orientationChange = true
      ret = true;
    }
    else {
    //Non-Mandatory in case of single use
    orientationChange = false;
    }

    return ret;
  }

 
  @override
  Widget build(BuildContext context) {
    if (checkOrientationChange(context)) {
      //Do Stuff if only once check is required. Else use the stub Variable. In this case, it is **orientationChange**.
    }



    //Using stub variable 
    Widget retWidget = orientationChange?Container():PlaceHolder();
    orientationChange = false;
    return retWidget;
    
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.