diff --git a/packages/flutter/lib/src/services/system_chrome.dart b/packages/flutter/lib/src/services/system_chrome.dart index a1d4c5395d..3d6881d658 100644 --- a/packages/flutter/lib/src/services/system_chrome.dart +++ b/packages/flutter/lib/src/services/system_chrome.dart @@ -368,6 +368,74 @@ abstract final class SystemChrome { /// /// ## Limitations /// + /// ### Android + /// + /// Android screens may choose to [letterbox](https://developer.android.com/guide/practices/enhanced-letterboxing) + /// applications that lock orientation, particularly on larger screens. When + /// letterboxing occurs on Android, the [MediaQueryData.size] reports the + /// letterboxed size, not the full screen size. Applications that make + /// decisions about whether to lock orientation based on the screen size + /// must use the `display` property of the current [FlutterView]. + /// + /// ```dart + /// // A widget that locks the screen to portrait if it is less than 600 + /// // logical pixels wide. + /// class MyApp extends StatefulWidget { + /// const MyApp({ super.key }); + /// + /// @override + /// State createState() => _MyAppState(); + /// } + /// + /// class _MyAppState extends State with WidgetsBindingObserver { + /// ui.Display? _display; + /// static const double kOrientationLockBreakpoint = 600; + /// + /// @override + /// void initState() { + /// super.initState(); + /// WidgetsBinding.instance.addObserver(this); + /// } + /// + /// @override + /// void didChangeDependencies() { + /// super.didChangeDependencies(); + /// _display = View.maybeOf(context)?.display; + /// } + /// + /// @override + /// void dispose() { + /// WidgetsBinding.instance.removeObserver(this); + /// _display = null; + /// super.dispose(); + /// } + /// + /// @override + /// void didChangeMetrics() { + /// final ui.Display? display = _display; + /// if (display == null) { + /// return; + /// } + /// if (display.size.width / display.devicePixelRatio < kOrientationLockBreakpoint) { + /// SystemChrome.setPreferredOrientations([ + /// DeviceOrientation.portraitUp, + /// ]); + /// } else { + /// SystemChrome.setPreferredOrientations([]); + /// } + /// } + /// + /// @override + /// Widget build(BuildContext context) { + /// return const MaterialApp( + /// home: Placeholder(), + /// ); + /// } + /// } + /// ``` + /// + /// ### iOS + /// /// This setting will only be respected on iPad if multitasking is disabled. /// /// You can decide to opt out of multitasking on iPad, then diff --git a/packages/flutter/lib/src/widgets/binding.dart b/packages/flutter/lib/src/widgets/binding.dart index f4778adfb3..14235ac8a8 100644 --- a/packages/flutter/lib/src/widgets/binding.dart +++ b/packages/flutter/lib/src/widgets/binding.dart @@ -139,10 +139,15 @@ abstract mixin class WidgetsBindingObserver { /// @override /// void initState() { /// super.initState(); + /// WidgetsBinding.instance.addObserver(this); + /// } + /// + /// @override + /// void didChangeDependencies() { + /// super.didChangeDependencies(); /// // [View.of] exposes the view from `WidgetsBinding.instance.platformDispatcher.views` /// // into which this widget is drawn. /// _lastSize = View.of(context).physicalSize; - /// WidgetsBinding.instance.addObserver(this); /// } /// /// @override