1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/// @docImport 'package:flutter/cupertino.dart';
6/// @docImport 'package:flutter/material.dart';
7library;
8
9import 'dart:async';
10import 'dart:ui';
11
12import 'package:flutter/foundation.dart';
13
14import 'binding.dart';
15import 'system_channels.dart';
16
17export 'dart:ui' show Brightness, Color;
18
19export 'binding.dart' show SystemUiChangeCallback;
20
21// Examples can assume:
22// import 'dart:ui' as ui;
23// import 'package:flutter/services.dart';
24// import 'package:flutter/material.dart';
25// import 'package:flutter/widgets.dart';
26// late BuildContext context;
27
28/// Specifies a particular device orientation.
29///
30/// To determine which values correspond to which orientations, first position
31/// the device in its default orientation (this is the orientation that the
32/// system first uses for its boot logo, or the orientation in which the
33/// hardware logos or markings are upright, or the orientation in which the
34/// cameras are at the top). If this is a portrait orientation, then this is
35/// [portraitUp]. Otherwise, it's [landscapeLeft]. As you rotate the device by
36/// 90 degrees in a counter-clockwise direction around the axis that pierces the
37/// screen, you step through each value in this enum in the order given.
38///
39/// For a device with a landscape default orientation, the orientation obtained
40/// by rotating the device 90 degrees clockwise from its default orientation is
41/// [portraitUp].
42///
43/// Used by [SystemChrome.setPreferredOrientations].
44enum DeviceOrientation {
45 /// If the device shows its boot logo in portrait, then the boot logo is shown
46 /// in [portraitUp]. Otherwise, the device shows its boot logo in landscape
47 /// and this orientation is obtained by rotating the device 90 degrees
48 /// clockwise from its boot orientation.
49 portraitUp,
50
51 /// The orientation that is 90 degrees counterclockwise from [portraitUp].
52 ///
53 /// If the device shows its boot logo in landscape, then the boot logo is
54 /// shown in [landscapeLeft].
55 landscapeLeft,
56
57 /// The orientation that is 180 degrees from [portraitUp].
58 portraitDown,
59
60 /// The orientation that is 90 degrees clockwise from [portraitUp].
61 landscapeRight,
62}
63
64/// Specifies a description of the application that is pertinent to the
65/// embedder's application switcher (also known as "recent tasks") user
66/// interface.
67///
68/// Used by [SystemChrome.setApplicationSwitcherDescription].
69@immutable
70class ApplicationSwitcherDescription {
71 /// Creates an ApplicationSwitcherDescription.
72 const ApplicationSwitcherDescription({this.label, this.primaryColor});
73
74 /// A label and description of the current state of the application.
75 final String? label;
76
77 /// The application's primary color.
78 ///
79 /// This may influence the color that the operating system uses to represent
80 /// the application.
81 final int? primaryColor;
82}
83
84/// Specifies a system overlay at a particular location.
85///
86/// Used by [SystemChrome.setEnabledSystemUIMode].
87enum SystemUiOverlay {
88 /// The status bar provided by the embedder on the top of the application
89 /// surface, if any.
90 top,
91
92 /// The status bar provided by the embedder on the bottom of the application
93 /// surface, if any.
94 bottom,
95}
96
97/// Describes different display configurations for both Android and iOS.
98///
99/// These modes mimic Android-specific display setups.
100///
101/// Used by [SystemChrome.setEnabledSystemUIMode].
102///
103/// Flutter apps use [SystemUiMode.edgeToEdge] by default and setting any
104/// of the other [SystemUiMode]s will NOT work unless you perform the migration
105/// detailed in
106/// https://docs.flutter.dev/release/breaking-changes/default-systemuimode-edge-to-edge.
107enum SystemUiMode {
108 /// Fullscreen display with status and navigation bars presentable by tapping
109 /// anywhere on the display.
110 ///
111 /// Available starting at Android SDK 4.1 (API 16). Earlier versions of Android
112 /// will not be affected by this setting. However, if your app targets Android
113 /// SDK 15 (API 35) or later (Flutter does this by default), then you must
114 /// migrate using the instructions in
115 /// https://docs.flutter.dev/release/breaking-changes/default-systemuimode-edge-to-edge
116 /// to use this mode.
117 ///
118 /// For applications running on iOS, the status bar and home indicator will be
119 /// hidden for a similar fullscreen experience.
120 ///
121 /// Tapping on the screen displays overlays, this gesture is not received by
122 /// the application.
123 ///
124 /// See also:
125 ///
126 /// * [SystemUiChangeCallback], used to listen and respond to the change in
127 /// system overlays.
128 leanBack,
129
130 /// Fullscreen display with status and navigation bars presentable through a
131 /// swipe gesture at the edges of the display.
132 ///
133 /// Available starting at Android SDK 4.4 (API 19). Earlier versions of
134 /// Android will not be affected by this setting. However, if your app targets
135 /// Android SDK 15 (API 35) or later (Flutter does this by default), then you
136 /// must migrate using the instructions in
137 /// https://docs.flutter.dev/release/breaking-changes/default-systemuimode-edge-to-edge
138 /// to use this mode.
139 ///
140 /// For applications running on iOS, the status bar and home indicator will be
141 /// hidden for a similar fullscreen experience.
142 ///
143 /// A swipe gesture from the edge of the screen displays overlays. In contrast
144 /// to [SystemUiMode.immersiveSticky], this gesture is not received by the
145 /// application.
146 ///
147 /// See also:
148 ///
149 /// * [SystemUiChangeCallback], used to listen and respond to the change in
150 /// system overlays.
151 immersive,
152
153 /// Fullscreen display with status and navigation bars presentable through a
154 /// swipe gesture at the edges of the display.
155 ///
156 /// Available starting at Android SDK 4.4 (API 19). Earlier versions of
157 /// Android will not be affected by this setting. However, if your app targets
158 /// Android SDK 15 (API 35) or later (Flutter does this by default), then you
159 /// must migrate using the instructions in
160 /// https://docs.flutter.dev/release/breaking-changes/default-systemuimode-edge-to-edge
161 /// to use this mode.
162 ///
163 /// For applications running on iOS, the status bar and home indicator will be
164 /// hidden for a similar fullscreen experience.
165 ///
166 /// A swipe gesture from the edge of the screen displays overlays. In contrast
167 /// to [SystemUiMode.immersive], this gesture is received by the application.
168 ///
169 /// See also:
170 ///
171 /// * [SystemUiChangeCallback], used to listen and respond to the change in
172 /// system overlays.
173 immersiveSticky,
174
175 /// Fullscreen display with status and navigation elements rendered over the
176 /// application.
177 ///
178 /// Available starting at Android SDK 10 (API 29). Earlier versions of Android
179 /// will not be affected by this setting.
180 ///
181 /// If your app targets Android SDK 15 (API 35) or later (Flutter does this by
182 /// default), then this mode is used by default on Android. This mode is also
183 /// used by default on iOS.
184 ///
185 /// For applications running on iOS, the status bar and home indicator will be
186 /// visible.
187 ///
188 /// The system overlays will not disappear or reappear in this mode as they
189 /// are permanently displayed on top of the application.
190 ///
191 /// See also:
192 ///
193 /// * [SystemUiOverlayStyle], can be used to configure transparent status and
194 /// navigation bars with or without a contrast scrim.
195 edgeToEdge,
196
197 /// Declares manually configured [SystemUiOverlay]s.
198 ///
199 /// When using this mode with [SystemChrome.setEnabledSystemUIMode], the
200 /// preferred overlays must be set by the developer.
201 ///
202 /// When [SystemUiOverlay.top] is enabled, the status bar will remain visible
203 /// on all platforms. Omitting this overlay will hide the status bar on iOS &
204 /// Android.
205 ///
206 /// When [SystemUiOverlay.bottom] is enabled, the navigation bar and home
207 /// indicator of Android and iOS applications will remain visible. Omitting this
208 /// overlay will hide them.
209 ///
210 /// Omitting both overlays will result in the same configuration as
211 /// [SystemUiMode.leanBack].
212 ///
213 /// If your app targets Android SDK 15 (API 35) or later, then you must
214 /// migrate using the instructions in
215 /// https://docs.flutter.dev/release/breaking-changes/default-systemuimode-edge-to-edge
216 /// to use this mode.
217 manual,
218}
219
220/// Specifies a preference for the style of the system overlays.
221///
222/// Used by [AppBar.systemOverlayStyle] for declaratively setting the style of
223/// the system overlays, and by [SystemChrome.setSystemUIOverlayStyle] for
224/// imperatively setting the style of the system overlays.
225@immutable
226class SystemUiOverlayStyle {
227 /// Creates a new [SystemUiOverlayStyle].
228 const SystemUiOverlayStyle({
229 this.systemNavigationBarColor,
230 this.systemNavigationBarDividerColor,
231 this.systemNavigationBarIconBrightness,
232 this.systemNavigationBarContrastEnforced,
233 this.statusBarColor,
234 this.statusBarBrightness,
235 this.statusBarIconBrightness,
236 this.systemStatusBarContrastEnforced,
237 });
238
239 /// The color of the system bottom navigation bar.
240 ///
241 /// Only honored in Android versions O and greater.
242 final Color? systemNavigationBarColor;
243
244 /// The color of the divider between the system's bottom navigation bar and the app's content.
245 ///
246 /// Only honored in Android versions P and greater.
247 final Color? systemNavigationBarDividerColor;
248
249 /// The brightness of the system navigation bar icons.
250 ///
251 /// Only honored in Android versions O and greater.
252 /// When set to [Brightness.light], the system navigation bar icons are light.
253 /// When set to [Brightness.dark], the system navigation bar icons are dark.
254 final Brightness? systemNavigationBarIconBrightness;
255
256 /// Overrides the contrast enforcement when setting a transparent navigation
257 /// bar.
258 ///
259 /// When setting a transparent navigation bar in SDK 29+, or Android 10 and up,
260 /// a translucent body scrim may be applied behind the button navigation bar
261 /// to ensure contrast with buttons and the background of the application.
262 ///
263 /// SDK 28-, or Android P and lower, will not apply this body scrim.
264 ///
265 /// Setting this to false overrides the default body scrim.
266 ///
267 /// See also:
268 ///
269 /// * [SystemUiOverlayStyle.systemNavigationBarColor], which is overridden
270 /// when transparent to enforce this contrast policy.
271 final bool? systemNavigationBarContrastEnforced;
272
273 /// The color of top status bar.
274 ///
275 /// Only honored in Android version M and greater.
276 final Color? statusBarColor;
277
278 /// The brightness of top status bar.
279 ///
280 /// Only honored in iOS.
281 final Brightness? statusBarBrightness;
282
283 /// The brightness of the top status bar icons.
284 ///
285 /// Only honored in Android version M and greater.
286 final Brightness? statusBarIconBrightness;
287
288 /// Overrides the contrast enforcement when setting a transparent status
289 /// bar.
290 ///
291 /// When setting a transparent status bar in SDK 29+, or Android 10 and up,
292 /// a translucent body scrim may be applied to ensure contrast with icons and
293 /// the background of the application.
294 ///
295 /// SDK 28-, or Android P and lower, will not apply this body scrim.
296 ///
297 /// Setting this to false overrides the default body scrim.
298 ///
299 /// See also:
300 ///
301 /// * [SystemUiOverlayStyle.statusBarColor], which is overridden
302 /// when transparent to enforce this contrast policy.
303 final bool? systemStatusBarContrastEnforced;
304
305 /// System overlays should be drawn with a light color. Intended for
306 /// applications with a dark background.
307 static const SystemUiOverlayStyle light = SystemUiOverlayStyle(
308 systemNavigationBarColor: Color(0xFF000000),
309 systemNavigationBarIconBrightness: Brightness.light,
310 statusBarIconBrightness: Brightness.light,
311 statusBarBrightness: Brightness.dark,
312 );
313
314 /// System overlays should be drawn with a dark color. Intended for
315 /// applications with a light background.
316 static const SystemUiOverlayStyle dark = SystemUiOverlayStyle(
317 systemNavigationBarColor: Color(0xFF000000),
318 systemNavigationBarIconBrightness: Brightness.light,
319 statusBarIconBrightness: Brightness.dark,
320 statusBarBrightness: Brightness.light,
321 );
322
323 /// Convert this event to a map for serialization.
324 Map<String, dynamic> _toMap() {
325 return <String, dynamic>{
326 'systemNavigationBarColor': systemNavigationBarColor?.value,
327 'systemNavigationBarDividerColor': systemNavigationBarDividerColor?.value,
328 'systemStatusBarContrastEnforced': systemStatusBarContrastEnforced,
329 'statusBarColor': statusBarColor?.value,
330 'statusBarBrightness': statusBarBrightness?.toString(),
331 'statusBarIconBrightness': statusBarIconBrightness?.toString(),
332 'systemNavigationBarIconBrightness': systemNavigationBarIconBrightness?.toString(),
333 'systemNavigationBarContrastEnforced': systemNavigationBarContrastEnforced,
334 };
335 }
336
337 @override
338 String toString() => '${objectRuntimeType(this, 'SystemUiOverlayStyle')}(${_toMap()})';
339
340 /// Creates a copy of this theme with the given fields replaced with new values.
341 SystemUiOverlayStyle copyWith({
342 Color? systemNavigationBarColor,
343 Color? systemNavigationBarDividerColor,
344 bool? systemNavigationBarContrastEnforced,
345 Color? statusBarColor,
346 Brightness? statusBarBrightness,
347 Brightness? statusBarIconBrightness,
348 bool? systemStatusBarContrastEnforced,
349 Brightness? systemNavigationBarIconBrightness,
350 }) {
351 return SystemUiOverlayStyle(
352 systemNavigationBarColor: systemNavigationBarColor ?? this.systemNavigationBarColor,
353 systemNavigationBarDividerColor:
354 systemNavigationBarDividerColor ?? this.systemNavigationBarDividerColor,
355 systemNavigationBarContrastEnforced:
356 systemNavigationBarContrastEnforced ?? this.systemNavigationBarContrastEnforced,
357 statusBarColor: statusBarColor ?? this.statusBarColor,
358 statusBarIconBrightness: statusBarIconBrightness ?? this.statusBarIconBrightness,
359 statusBarBrightness: statusBarBrightness ?? this.statusBarBrightness,
360 systemStatusBarContrastEnforced:
361 systemStatusBarContrastEnforced ?? this.systemStatusBarContrastEnforced,
362 systemNavigationBarIconBrightness:
363 systemNavigationBarIconBrightness ?? this.systemNavigationBarIconBrightness,
364 );
365 }
366
367 @override
368 int get hashCode => Object.hash(
369 systemNavigationBarColor,
370 systemNavigationBarDividerColor,
371 systemNavigationBarContrastEnforced,
372 statusBarColor,
373 statusBarBrightness,
374 statusBarIconBrightness,
375 systemStatusBarContrastEnforced,
376 systemNavigationBarIconBrightness,
377 );
378
379 @override
380 bool operator ==(Object other) {
381 if (other.runtimeType != runtimeType) {
382 return false;
383 }
384 return other is SystemUiOverlayStyle &&
385 other.systemNavigationBarColor == systemNavigationBarColor &&
386 other.systemNavigationBarDividerColor == systemNavigationBarDividerColor &&
387 other.systemNavigationBarContrastEnforced == systemNavigationBarContrastEnforced &&
388 other.statusBarColor == statusBarColor &&
389 other.statusBarIconBrightness == statusBarIconBrightness &&
390 other.statusBarBrightness == statusBarBrightness &&
391 other.systemStatusBarContrastEnforced == systemStatusBarContrastEnforced &&
392 other.systemNavigationBarIconBrightness == systemNavigationBarIconBrightness;
393 }
394}
395
396List<String> _stringify(List<dynamic> list) => <String>[
397 for (final dynamic item in list) item.toString(),
398];
399
400/// Controls specific aspects of the operating system's graphical interface and
401/// how it interacts with the application.
402abstract final class SystemChrome {
403 /// Specifies the set of orientations the application interface can
404 /// be displayed in.
405 ///
406 /// The `orientation` argument is a list of [DeviceOrientation] enum values.
407 /// The empty list causes the application to defer to the operating system
408 /// default.
409 ///
410 /// ## Limitations
411 ///
412 /// ### Android
413 ///
414 /// Android limits the [orientations](https://developer.android.com/reference/android/R.attr#screenOrientation)
415 /// to the following combinations:
416 ///
417 /// - None (empty) - Corresponds to unspecified
418 /// - portraitUp - Corresponds to portrait
419 /// - landscapeLeft - Corresponds to landscape
420 /// - portraitDown - Corresponds to reversePortrait
421 /// - portraitUp, portraitDown - Corresponds to userPortrait
422 /// - landscapeRight - Corresponds to reverseLandscape
423 /// - landscapeLeft, landscapeRight - Corresponds to userLandscape
424 /// - portraitUp, landscapeLeft, landscapeRight - Corresponds to user
425 /// - portraitUp, portraitDown, landscapeLeft, landscapeRight - Corresponds
426 /// to fullUser
427 ///
428 /// Android screens may choose to [letterbox](https://developer.android.com/guide/practices/enhanced-letterboxing)
429 /// applications that lock orientation, particularly on larger screens. When
430 /// letterboxing occurs on Android, the [MediaQueryData.size] reports the
431 /// letterboxed size, not the full screen size. Applications that make
432 /// decisions about whether to lock orientation based on the screen size
433 /// must use the `display` property of the current [FlutterView].
434 ///
435 /// ```dart
436 /// // A widget that locks the screen to portrait if it is less than 600
437 /// // logical pixels wide.
438 /// class MyApp extends StatefulWidget {
439 /// const MyApp({ super.key });
440 ///
441 /// @override
442 /// State<MyApp> createState() => _MyAppState();
443 /// }
444 ///
445 /// class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
446 /// ui.FlutterView? _view;
447 /// static const double kOrientationLockBreakpoint = 600;
448 ///
449 /// @override
450 /// void initState() {
451 /// super.initState();
452 /// WidgetsBinding.instance.addObserver(this);
453 /// }
454 ///
455 /// @override
456 /// void didChangeDependencies() {
457 /// super.didChangeDependencies();
458 /// _view = View.maybeOf(context);
459 /// }
460 ///
461 /// @override
462 /// void dispose() {
463 /// WidgetsBinding.instance.removeObserver(this);
464 /// _view = null;
465 /// super.dispose();
466 /// }
467 ///
468 /// @override
469 /// void didChangeMetrics() {
470 /// final ui.Display? display = _view?.display;
471 /// if (display == null) {
472 /// return;
473 /// }
474 /// if (display.size.width / display.devicePixelRatio < kOrientationLockBreakpoint) {
475 /// SystemChrome.setPreferredOrientations(<DeviceOrientation>[
476 /// DeviceOrientation.portraitUp,
477 /// ]);
478 /// } else {
479 /// SystemChrome.setPreferredOrientations(<DeviceOrientation>[]);
480 /// }
481 /// }
482 ///
483 /// @override
484 /// Widget build(BuildContext context) {
485 /// return const MaterialApp(
486 /// home: Placeholder(),
487 /// );
488 /// }
489 /// }
490 /// ```
491 ///
492 /// ### iOS
493 ///
494 /// This setting will only be respected on iPad if multitasking is disabled.
495 ///
496 /// You can decide to opt out of multitasking on iPad, then
497 /// setPreferredOrientations will work but your app will not
498 /// support Slide Over and Split View multitasking anymore.
499 ///
500 /// Should you decide to opt out of multitasking you can do this by
501 /// setting "Requires full screen" to true in the Xcode Deployment Info.
502 static Future<void> setPreferredOrientations(List<DeviceOrientation> orientations) async {
503 await SystemChannels.platform.invokeMethod<void>(
504 'SystemChrome.setPreferredOrientations',
505 _stringify(orientations),
506 );
507 }
508
509 /// Specifies the description of the current state of the application as it
510 /// pertains to the application switcher (also known as "recent tasks").
511 ///
512 /// Any part of the description that is unsupported on the current platform
513 /// will be ignored.
514 static Future<void> setApplicationSwitcherDescription(
515 ApplicationSwitcherDescription description,
516 ) async {
517 await SystemChannels.platform.invokeMethod<void>(
518 'SystemChrome.setApplicationSwitcherDescription',
519 <String, dynamic>{'label': description.label, 'primaryColor': description.primaryColor},
520 );
521 }
522
523 /// Specifies the [SystemUiMode] to have visible when the application
524 /// is running.
525 ///
526 /// The `overlays` argument is a list of [SystemUiOverlay] enum values
527 /// denoting the overlays to show when configured with [SystemUiMode.manual].
528 ///
529 /// If a particular mode is unsupported on the platform, enabling or
530 /// disabling that mode will be ignored.
531 ///
532 /// The settings here can be overridden by the platform when System UI becomes
533 /// necessary for functionality.
534 ///
535 /// For example, on Android, when the keyboard becomes visible, it will enable the
536 /// navigation bar and status bar system UI overlays. When the keyboard is closed,
537 /// Android will not restore the previous UI visibility settings, and the UI
538 /// visibility cannot be changed until 1 second after the keyboard is closed to
539 /// prevent malware locking users from navigation buttons.
540 ///
541 /// To regain "fullscreen" after text entry, the UI overlays can be set again
542 /// after a delay of at least 1 second through [restoreSystemUIOverlays] or
543 /// calling this again. Otherwise, the original UI overlay settings will be
544 /// automatically restored only when the application loses and regains focus.
545 ///
546 /// Alternatively, a [SystemUiChangeCallback] can be provided to respond to
547 /// changes in the System UI. This will be called, for example, when in
548 /// [SystemUiMode.leanBack] and the user taps the screen to bring up the
549 /// system overlays. The callback provides a boolean to represent if the
550 /// application is currently in a fullscreen mode or not, so that the
551 /// application can respond to these changes. When `systemOverlaysAreVisible`
552 /// is true, the application is not fullscreen. See
553 /// [SystemChrome.setSystemUIChangeCallback] to respond to these changes in a
554 /// fullscreen application.
555 ///
556 /// If your app targets Android SDK 15 (API 35) or later (Flutter does this by
557 /// default), then your Flutter app uses [SystemUiMode.edgeToEdge] by default
558 /// on Android and setting any of the other [SystemUiMode]s will NOT work
559 /// unless you perform the migration detailed in
560 /// https://docs.flutter.dev/release/breaking-changes/default-systemuimode-edge-to-edge.
561 static Future<void> setEnabledSystemUIMode(
562 SystemUiMode mode, {
563 List<SystemUiOverlay>? overlays,
564 }) async {
565 if (mode != SystemUiMode.manual) {
566 await SystemChannels.platform.invokeMethod<void>(
567 'SystemChrome.setEnabledSystemUIMode',
568 mode.toString(),
569 );
570 } else {
571 assert(mode == SystemUiMode.manual && overlays != null);
572 await SystemChannels.platform.invokeMethod<void>(
573 'SystemChrome.setEnabledSystemUIOverlays',
574 _stringify(overlays!),
575 );
576 }
577 }
578
579 /// Sets the callback method for responding to changes in the system UI.
580 ///
581 /// This is relevant when using [SystemUiMode.leanBack]
582 /// and [SystemUiMode.immersive] and [SystemUiMode.immersiveSticky] on Android
583 /// platforms, where the [SystemUiOverlay]s can appear and disappear based on
584 /// user interaction.
585 ///
586 /// This will be called, for example, when in [SystemUiMode.leanBack] and the
587 /// user taps the screen to bring up the system overlays. The callback
588 /// provides a boolean to represent if the application is currently in a
589 /// fullscreen mode or not, so that the application can respond to these
590 /// changes. When `systemOverlaysAreVisible` is true, the application is not
591 /// fullscreen.
592 ///
593 /// When using [SystemUiMode.edgeToEdge], system overlays are always visible
594 /// and do not change. When manually configuring [SystemUiOverlay]s with
595 /// [SystemUiMode.manual], this callback will only be triggered when all
596 /// overlays have been disabled. This results in the same behavior as
597 /// [SystemUiMode.leanBack].
598 ///
599 static Future<void> setSystemUIChangeCallback(SystemUiChangeCallback? callback) async {
600 ServicesBinding.instance.setSystemUiChangeCallback(callback);
601 // Skip setting up the listener if there is no callback.
602 if (callback != null) {
603 await SystemChannels.platform.invokeMethod<void>('SystemChrome.setSystemUIChangeListener');
604 }
605 }
606
607 /// Restores the system overlays to the last settings provided via
608 /// [setEnabledSystemUIMode]. May be used when the platform force enables/disables
609 /// UI elements.
610 ///
611 /// For example, when the Android keyboard disables hidden status and navigation bars,
612 /// this can be called to re-disable the bars when the keyboard is closed.
613 ///
614 /// On Android, the system UI cannot be changed until 1 second after the previous
615 /// change. This is to prevent malware from permanently hiding navigation buttons.
616 static Future<void> restoreSystemUIOverlays() async {
617 await SystemChannels.platform.invokeMethod<void>('SystemChrome.restoreSystemUIOverlays');
618 }
619
620 /// Specifies the style to use for the system overlays (e.g. the status bar on
621 /// Android or iOS, the system navigation bar on Android) that are visible (if any).
622 ///
623 /// This method will schedule the embedder update to be run in a microtask.
624 /// Any subsequent calls to this method during the current event loop will
625 /// overwrite the pending value, such that only the last specified value takes
626 /// effect.
627 ///
628 /// Call this API in code whose lifecycle matches that of the desired
629 /// system UI styles. For instance, to change the system UI style on a new
630 /// page, consider calling when pushing/popping a new [PageRoute].
631 ///
632 /// The [AppBar] widget automatically sets the system overlay style based on
633 /// its [AppBar.systemOverlayStyle], so configure that instead of calling this
634 /// method directly. Likewise, do the same for [CupertinoNavigationBar] via
635 /// [CupertinoNavigationBar.backgroundColor].
636 ///
637 /// If a particular style is not supported on the platform, selecting it will
638 /// have no effect.
639 ///
640 /// {@tool sample}
641 /// The following example uses an `AppBar` to set the system status bar color and
642 /// the system navigation bar color.
643 ///
644 /// ** See code in examples/api/lib/services/system_chrome/system_chrome.set_system_u_i_overlay_style.0.dart **
645 /// {@end-tool}
646 ///
647 /// For more complex control of the system overlay styles, consider using
648 /// an [AnnotatedRegion] widget instead of calling [setSystemUIOverlayStyle]
649 /// directly. This widget places a value directly into the layer tree where
650 /// it can be hit-tested by the framework. On every frame, the framework will
651 /// hit-test and select the annotated region it finds under the status and
652 /// navigation bar and synthesize them into a single style. This can be used
653 /// to configure the system styles when an app bar is not used. When an app
654 /// bar is used, apps should not enclose the app bar in an annotated region
655 /// because one is automatically created. If an app bar is used and the app
656 /// bar is enclosed in an annotated region, the app bar overlay style supersedes
657 /// the status bar properties defined in the enclosing annotated region overlay
658 /// style and the enclosing annotated region overlay style supersedes the app bar
659 /// overlay style navigation bar properties.
660 ///
661 /// {@tool sample}
662 /// The following example uses an `AnnotatedRegion<SystemUiOverlayStyle>` to set
663 /// the system status bar color and the system navigation bar color.
664 ///
665 /// ** See code in examples/api/lib/services/system_chrome/system_chrome.set_system_u_i_overlay_style.1.dart **
666 /// {@end-tool}
667 ///
668 /// To imperatively set the style of the system overlays, use [SystemChrome.setSystemUIOverlayStyle].
669 ///
670 /// {@tool snippet}
671 /// The following example uses SystemChrome to set the status bar icon brightness based on system brightness.
672 /// ```dart
673 /// final Brightness brightness = MediaQuery.platformBrightnessOf(context);
674 /// SystemChrome.setSystemUIOverlayStyle(
675 /// SystemUiOverlayStyle(
676 /// statusBarIconBrightness: brightness == Brightness.dark ? Brightness.light : Brightness.dark,
677 /// ),
678 /// );
679 /// ```
680 /// {@end-tool}
681 ///
682 /// See also:
683 ///
684 /// * [AppBar.systemOverlayStyle], a convenient property for declaratively setting
685 /// the style of the system overlays.
686 /// * [AnnotatedRegion], the widget used to place a `SystemUiOverlayStyle` into
687 /// the layer tree.
688 static void setSystemUIOverlayStyle(SystemUiOverlayStyle style) {
689 if (_pendingStyle != null) {
690 // The microtask has already been queued; just update the pending value.
691 _pendingStyle = style;
692 return;
693 }
694 if (style == _latestStyle) {
695 // Trivial success: no microtask has been queued and the given style is
696 // already in effect, so no need to queue a microtask.
697 return;
698 }
699 _pendingStyle = style;
700 scheduleMicrotask(() {
701 assert(_pendingStyle != null);
702 if (_pendingStyle != _latestStyle) {
703 SystemChannels.platform.invokeMethod<void>(
704 'SystemChrome.setSystemUIOverlayStyle',
705 _pendingStyle!._toMap(),
706 );
707 _latestStyle = _pendingStyle;
708 }
709 _pendingStyle = null;
710 });
711 }
712
713 /// Called by the binding during a transition to a new app lifecycle state.
714 static void handleAppLifecycleStateChanged(AppLifecycleState state) {
715 // When the app is detached, clear the record of the style sent to the host
716 // so that it will be sent again when the app is reattached.
717 if (state == AppLifecycleState.detached) {
718 scheduleMicrotask(() {
719 _latestStyle = null;
720 });
721 }
722 }
723
724 static SystemUiOverlayStyle? _pendingStyle;
725
726 /// The last style that was set using [SystemChrome.setSystemUIOverlayStyle].
727 @visibleForTesting
728 static SystemUiOverlayStyle? get latestStyle => _latestStyle;
729 static SystemUiOverlayStyle? _latestStyle;
730}
731

Provided by KDAB

Privacy Policy
Learn more about Flutter for embedded and desktop on industrialflutter.com