Flutter:在平板设备上强制竖屏界面(iOS与 Android),即使设备处于横屏状态,也要避免出现黑边
我有一个Flutter应用,手机和平板上应该保持竖屏模式。
我想要的:
- 即使用户把设备横向持握,应用也应保持竖屏界面。
- 我无法创建横向布局
- 我希望应用仍然看起来全屏显示(没有黑边/信箱效应)
当前设置(Flutter):
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
runApp(const MyApp());
}
iOS Info.plist 目前同时支持竖屏和横屏(iPad也一样)。
问题:
- 在iPad模拟器和某些Android平板上,应用仍然会旋转到横屏。
- 如果我移除横屏方向,应用仍保持竖屏,但在设备处于横屏方向时会出现黑边/留白(竖屏界面被居中,周围有空白区域)。
- 我想要在横屏时仍然是竖屏UI的全屏显示(没有留白)。就像某些游戏或应用那样。
问题:
- 在设备横屏时,是否在iOS和 Android 上技术上可以在不支持横屏布局的情况下,保持竖屏界面全屏?
- 如果不能,针对平板设备应该采用什么推荐做法?(例如:允许横屏但保持竖屏风格的居中布局,或放弃iPad的多任务处理等。)
任何指导或对平台限制的解释都会有帮助。
解决方案
在手机和平板上实现无黑边的竖屏显示当然是可行的,但这需要除Flutter代码之外的平台特定配置。下面是对我有用的方法:
Flutter(你已经有这个)
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
runApp(const MyApp());
}
这单靠这段在iPads和某些Android平板上并不起作用。
iOS — iPad问题
iPad忽略竖屏锁定的原因是因为多任务处理。苹果要求支持Split View/Slide Over的应用必须支持所有方向。因此你的竖屏锁定会被忽略。
解决办法是放弃对多任务处理的支持。
在你的 Info.plist 中:
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
</array>
<key>UIRequiresFullScreen</key>
<true/>
那段 UIRequiresFullScreen 就是关键。它告诉iOS应用不支持Split View,因此不会强制横屏,也不会添加留黑边。应用将保持全屏竖屏。
在Xcode中也要:前往Runner → General → Deployment Info,确保只勾选Portrait,并且勾选“Requires full screen”。
为了更安全,在 AppDelegate.swift:
override func application(
_ application: UIApplication,
supportedInterfaceOrientationsFor window: UIWindow?
) -> UIInterfaceOrientationMask {
return .portrait
}
Android
在 AndroidManifest.xml 中,向你的Activity添加 screenOrientation:
<activity
android:name=".MainActivity"
android:screenOrientation="portrait"
android:resizeableActivity="false"
...>
screenOrientation="portrait" 将其锁定。resizeableActivity="false" 处理可能让你进入多窗口模式的平板和折叠设备。
你也可以在 MainActivity.kt 中作为备选进行设置:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
}
你会失去什么
先说清楚——使用这种设置,你将失去iPad的 Split View/Slide Over以及Android的多窗口功能。苹果仍然接受这类应用,很多游戏和相机应用也这样做。你将错过“Designed for iPad”之类的多任务处理体验。
如果你不想失去多任务处理
另一种做法是允许横屏,但保持居中的竖屏形状布局:
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth > constraints.maxHeight) {
return Scaffold(
backgroundColor: Colors.black,
body: Center(
child: AspectRatio(
aspectRatio: 9 / 16,
child: MyPortraitContent(),
),
),
);
}
return MyPortraitContent();
},
)
这会在横屏时给你一个居中显示的竖屏布局,背景颜色由你控制,而不是操作系统自动添加难看的黑边。尽管从技术上仍然是两边留白的竖屏布局,只是由你来控制。