【问题标题】:How does Flutter handle orientation changeFlutter 如何处理方向变化
【发布时间】:2026-01-05 20:20:03
【问题描述】:

方向更改处理是否像在 Flutter 中使用更新的尺寸重新运行小部件的构建一样简单?

我问是因为在 Android 中,整个 Activity 都会被重建,这就是为什么所有信息都通过 Intent 发送的原因。

在设计小部件时要记住哪些问题,以便它们处理方向更改或导致 UI 更改的其他更改?

【问题讨论】:

    标签: flutter dart orientation


    【解决方案1】:

    基本上 - 是的!现在,更具体地说,MediaQuery 小部件侦听方向/大小/布局更改并重建它的子级。此小部件已经是 MaterialAppWidgetsApp 小部件的一部分,因此您可能不需要包含它。

    如果您希望您的小部件利用设备方向,您可以使用MediaQuery.of 静态成员来访问包含设备方向的MediaQueryData。例如,一个以纵向和横向显示不同文本的简单小部件(需要是 MaterialAppWidgetsAppMediaQuery 的子级)。

    class MyWidget extends StatelessWidget {
      Widget build(BuildContext context) {
        final mediaQueryData = MediaQuery.of(context);
        if (mediaQueryData.orientation == Orientation.landscape) {
          return const Text('landscape');
        }
        return const Text('portrait!');
      }
    }
    

    【讨论】:

      【解决方案2】:

      这将帮助您强制 Flutter 应用程序保持在纵向(垂直)模式,即使用户正在旋转智能手机

          void main(){
        ///
        /// Force the layout to Portrait mode
        /// 
        SystemChrome.setPreferredOrientations([
          DeviceOrientation.portraitUp,
          DeviceOrientation.portraitDown
        ]);
      
        runApp(new MyApp());
      }
      

      【讨论】:

      • 这与问题完全无关
      【解决方案3】:

      根据这个doc,你可以使用OrientationBuilder

      OrientationBuilder(
        builder: (context, orientation) {
          if (orientation == Orientation.portrait) 
               // return A
          else 
              // return B
      });
      

      【讨论】:

        【解决方案4】:

        虽然上面 Jonah 的回答是正确的,但就我个人而言,我建议使用 switch 而不是 if

        需要在相关函数中实现不同的内容。

        @override
        Widget build(BuildContext context) {
          switch (MediaQuery.of(context).orientation) {
            case Orientation.landscape:
              return _landscapeContent();
            case Orientation.portrait:
            default:
              return _portraitContent();
          }
        }
        

        更新

        另一方面,当您有一个内部布尔值 _fullscreen 标志时,您保持全屏状态(假设您在某处有一个全屏按钮,并且即使手机处于纵向模式也希望显示该内容),然后if 会更方便。

        @override
        Widget build(BuildContext context) {
          final orientation = MediaQuery.of(context).orientation;
          if (orientation == Orientation.landscape || _fullscreen) {
            return _landscapeContent();
          }
          return _portraitContent();
        }
        

        【讨论】:

          【解决方案5】:

          要确定应用的当前Orientation,请使用OrientationBuilder 小部件。 OrientationBuilder 通过比较父小部件可用的宽度和高度来计算当前的Orientation,并在父窗口大小改变时重建。

          使用Orientation,构建一个在纵向模式下显示两列或在横向模式下显示三列的列表。

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

          完整示例

          import 'package:flutter/material.dart';
          
          void main() {
            runApp(const MyApp());
          }
          
          class MyApp extends StatelessWidget {
            const MyApp({Key? key}) : super(key: key);
          
            @override
            Widget build(BuildContext context) {
              const appTitle = 'Orientation Demo';
          
              return const MaterialApp(
                title: appTitle,
                home: OrientationList(
                  title: appTitle,
                ),
              );
            }
          }
          
          class OrientationList extends StatelessWidget {
            final String title;
          
            const OrientationList({Key? key, required this.title}) : super(key: key);
          
            @override
            Widget build(BuildContext context) {
              return Scaffold(
                appBar: AppBar(title: Text(title)),
                body: OrientationBuilder(
                  builder: (context, orientation) {
                    return GridView.count(
                      // Create a grid with 2 columns in portrait mode, or 3 columns in
                      // landscape mode.
                      crossAxisCount: orientation == Orientation.portrait ? 2 : 3,
                      // Generate 100 widgets that display their index in the List.
                      children: List.generate(100, (index) {
                        return Center(
                          child: Text(
                            'Item $index',
                            style: Theme.of(context).textTheme.headline1,
                          ),
                        );
                      }),
                    );
                  },
                ),
              );
            }
          }
          

          【讨论】:

            最近更新 更多