Flutter 如何处理方向变化
How does Flutter handle orientation change
方向更改处理是否像在 Flutter 中使用更新后的尺寸重新运行小部件的构建一样简单?
我问是因为在Android中,整个Activity都被重建了,这就是为什么所有的信息都是通过intents发送的。
在设计小部件时是否需要牢记任何陷阱,以便它们能够处理方向变化或导致 UI 发生变化的其他变化?
基本上 - 是的!现在,更具体地说,MediaQuery
小部件侦听 orientation/size/layout 更改并重建它的子项。此小部件已经是 MaterialApp
和 WidgetsApp
小部件的一部分,因此您可能不需要包含它。
如果您希望小部件利用设备方向,可以使用 MediaQuery.of
静态成员访问包含设备方向的 MediaQueryData
。例如,一个以纵向和横向显示不同文本的简单小部件(需要是 MaterialApp
、WidgetsApp
或 MediaQuery
的子项)。
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!');
}
}
这将帮助您强制 Flutter 应用程序保持纵向(垂直)模式,即使用户正在旋转智能手机也是如此
void main(){
///
/// Force the layout to Portrait mode
///
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown
]);
runApp(new MyApp());
}
虽然 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
标志时,你将保持全屏状态(假设你在某处有一个全屏按钮并且想要显示该内容,即使 phone),然后if
会更方便。
@override
Widget build(BuildContext context) {
final orientation = MediaQuery.of(context).orientation;
if (orientation == Orientation.landscape || _fullscreen) {
return _landscapeContent();
}
return _portraitContent();
}
根据这个 doc 你可以使用 OrientationBuilder
.
OrientationBuilder(
builder: (context, orientation) {
if (orientation == Orientation.portrait)
// return A
else
// return B
});
要确定应用的当前 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,
),
);
}),
);
},
),
);
}
}
方向更改处理是否像在 Flutter 中使用更新后的尺寸重新运行小部件的构建一样简单?
我问是因为在Android中,整个Activity都被重建了,这就是为什么所有的信息都是通过intents发送的。
在设计小部件时是否需要牢记任何陷阱,以便它们能够处理方向变化或导致 UI 发生变化的其他变化?
基本上 - 是的!现在,更具体地说,MediaQuery
小部件侦听 orientation/size/layout 更改并重建它的子项。此小部件已经是 MaterialApp
和 WidgetsApp
小部件的一部分,因此您可能不需要包含它。
如果您希望小部件利用设备方向,可以使用 MediaQuery.of
静态成员访问包含设备方向的 MediaQueryData
。例如,一个以纵向和横向显示不同文本的简单小部件(需要是 MaterialApp
、WidgetsApp
或 MediaQuery
的子项)。
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!');
}
}
这将帮助您强制 Flutter 应用程序保持纵向(垂直)模式,即使用户正在旋转智能手机也是如此
void main(){
///
/// Force the layout to Portrait mode
///
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown
]);
runApp(new MyApp());
}
虽然 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
标志时,你将保持全屏状态(假设你在某处有一个全屏按钮并且想要显示该内容,即使 phone),然后if
会更方便。
@override
Widget build(BuildContext context) {
final orientation = MediaQuery.of(context).orientation;
if (orientation == Orientation.landscape || _fullscreen) {
return _landscapeContent();
}
return _portraitContent();
}
根据这个 doc 你可以使用 OrientationBuilder
.
OrientationBuilder(
builder: (context, orientation) {
if (orientation == Orientation.portrait)
// return A
else
// return B
});
要确定应用的当前 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,
),
);
}),
);
},
),
);
}
}