mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Closes https://github.com/flutter/flutter/issues/177330 Contributes to https://github.com/flutter/flutter/issues/175878 ### Description This PR implements support for three new iOS accessibility motion features. - `Auto-Play Animated Images`: Informs the app when the user has chosen to pause automatically playing GIFs and other animated content. - `Auto-Play Video Previews`: Informs the app when the user has disabled the automatic playback of video previews. - `Prefer Non-Blinking Cursor`: Informs the app that the user prefers a non-blinking text insertion indicator in editable text fields. The original issue requested seven features. I was able to find and implement features with clear, public, and general-purpose APIs. The remaining features were not included for the following reasons: - `Vehicle Motion Cues`: No public API found. - `Auto-Play Message Effects`: No public API found. This is likely a feature exclusive to the Messages framework. - `Limit Frame Rate`: No public API found. - `Dim Flashing Lights`: There is a public API available [MADimFlashingLightsEnabled](https://developer.apple.com/documentation/mediaaccessibility/madimflashinglightsenabled()). It is intended for media playback frameworks. It's unclear if exposing this feature is necessary or actionable for a general-purpose application UI. | Feature Name | API | Flutter AccessibilityFeatures | | :-: | :-: | :-: | | Vehicle Motion Cues | - | - | | Dim Flashing Lights | [MADimFlashingLightsEnabled](https://developer.apple.com/documentation/mediaaccessibility/madimflashinglightsenabled()) | - | | Auto-Play Animated Images | [animatedImagesEnabled](https://developer.apple.com/documentation/accessibility/accessibilitysettings/animatedimagesenabled) | autoPlayAnimatedImages | | Auto-Play Video Previews | [isVideoAutoplayEnabled](https://developer.apple.com/documentation/uikit/uiaccessibility/isvideoautoplayenabled) | autoPlayVideos | | Auto-Play Message Effects | - | - | | Prefer Non-Blinking Cursor | [prefersNonBlinkingTextInsertionIndicator](https://developer.apple.com/documentation/accessibility/accessibilitysettings/prefersnonblinkingtextinsertionindicator) | deterministicCursor | | Limit Frame Rate | - | - | The `AccessibilityFeatures.swift` was introduced to refactor all native iOS accessibility logic into a single, dedicated class. This change moves the responsibility of querying settings and observing notifications out of `FlutterViewController.mm`, which cleans up the controller, simplifies future maintenance, and makes logic unit-testable. ### Demo https://github.com/user-attachments/assets/1b3e7a2f-03b4-4716-959e-dbeea938e4d2 <details closed><summary>Code sample</summary> ```dart import 'package:flutter/material.dart'; void main() { runApp( MaterialApp( debugShowCheckedModeBanner: false, home: Screen(), ), ); } class Screen extends StatefulWidget { @override State<Screen> createState() => _ScreenState(); } class _ScreenState extends State<Screen> with WidgetsBindingObserver { @override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); } @override void didChangeAccessibilityFeatures() { super.didChangeAccessibilityFeatures(); if (mounted) { setState(() {}); } } @override void dispose() { WidgetsBinding.instance.removeObserver(this); super.dispose(); } @override Widget build(BuildContext context) { final accessibilityFeatures = View.of( context, ).platformDispatcher.accessibilityFeatures; return Scaffold( body: Center( child: Column( spacing: 10, mainAxisAlignment: MainAxisAlignment.center, children: [ for (final feature in [ 'accessibleNavigation: ${accessibilityFeatures.accessibleNavigation}', 'invertColors: ${accessibilityFeatures.invertColors}', 'disableAnimations: ${accessibilityFeatures.disableAnimations}', 'boldText: ${accessibilityFeatures.boldText}', 'reduceMotion: ${accessibilityFeatures.reduceMotion}', 'highContrast: ${accessibilityFeatures.highContrast}', 'onOffSwitchLabels: ${accessibilityFeatures.onOffSwitchLabels}', 'supportsAnnounce: ${accessibilityFeatures.supportsAnnounce}', 'autoPlayAnimatedImages: ${accessibilityFeatures.autoPlayAnimatedImages}', 'autoPlayVideos: ${accessibilityFeatures.autoPlayVideos}', 'deterministicCursor: ${accessibilityFeatures.deterministicCursor}', ]) Text(feature), ], ), ), ); } } ``` </details> ## Pre-launch Checklist - [X] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [X] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [X] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [X] I signed the [CLA]. - [X] I listed at least one issue that this PR fixes in the description above. - [X] I updated/added relevant documentation (doc comments with `///`). - [X] I added new tests to check the change I am making, or this PR is [test-exempt]. - [X] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [X] All existing and new tests are passing. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md --------- Co-authored-by: chunhtai <47866232+chunhtai@users.noreply.github.com>