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/services.dart';
6/// @docImport 'package:flutter/widgets.dart';
7library;
8
9import 'package:flutter/foundation.dart';
10import 'package:flutter/painting.dart';
11
12export 'dart:ui' show TextDirection;
13
14/// Determines the assertiveness level of the accessibility announcement.
15///
16/// It is used by [AnnounceSemanticsEvent] to determine the priority with which
17/// assistive technology should treat announcements.
18enum Assertiveness {
19 /// The assistive technology will speak changes whenever the user is idle.
20 polite,
21
22 /// The assistive technology will interrupt any announcement that it is
23 /// currently making to notify the user about the change.
24 ///
25 /// It should only be used for time-sensitive/critical notifications.
26 assertive,
27}
28
29/// An event sent by the application to notify interested listeners that
30/// something happened to the user interface (e.g. a view scrolled).
31///
32/// These events are usually interpreted by assistive technologies to give the
33/// user additional clues about the current state of the UI.
34abstract class SemanticsEvent {
35 /// Initializes internal fields.
36 ///
37 /// [type] is a string that identifies this class of [SemanticsEvent]s.
38 const SemanticsEvent(this.type);
39
40 /// The type of this event.
41 ///
42 /// The type is used by the engine to translate this event into the
43 /// appropriate native event (`UIAccessibility*Notification` on iOS and
44 /// `AccessibilityEvent` on Android).
45 final String type;
46
47 /// Converts this event to a Map that can be encoded with
48 /// [StandardMessageCodec].
49 ///
50 /// [nodeId] is the unique identifier of the semantics node associated with
51 /// the event, or null if the event is not associated with a semantics node.
52 Map<String, dynamic> toMap({int? nodeId}) {
53 final Map<String, dynamic> event = <String, dynamic>{'type': type, 'data': getDataMap()};
54 if (nodeId != null) {
55 event['nodeId'] = nodeId;
56 }
57
58 return event;
59 }
60
61 /// Returns the event's data object.
62 Map<String, dynamic> getDataMap();
63
64 @override
65 String toString() {
66 final List<String> pairs = <String>[];
67 final Map<String, dynamic> dataMap = getDataMap();
68 final List<String> sortedKeys = dataMap.keys.toList()..sort();
69 for (final String key in sortedKeys) {
70 pairs.add('$key: ${dataMap[key]}');
71 }
72 return '${objectRuntimeType(this, 'SemanticsEvent')}(${pairs.join(', ')})';
73 }
74}
75
76/// An event for a semantic announcement.
77///
78/// This should be used for announcement that are not seamlessly announced by
79/// the system as a result of a UI state change.
80///
81/// For example a camera application can use this method to make accessibility
82/// announcements regarding objects in the viewfinder.
83///
84/// When possible, prefer using mechanisms like [Semantics] to implicitly
85/// trigger announcements over using this event.
86///
87/// ### Android
88/// Android has [deprecated announcement events][1] due to its disruptive
89/// behavior with TalkBack forcing it to clear its speech queue and speak the
90/// provided text. Instead, use mechanisms like [Semantics] to implicitly
91/// trigger announcements.
92///
93/// [1]: https://developer.android.com/reference/android/view/View#announceForAccessibility(java.lang.CharSequence)
94///
95class AnnounceSemanticsEvent extends SemanticsEvent {
96 /// Constructs an event that triggers an announcement by the platform.
97 const AnnounceSemanticsEvent(
98 this.message,
99 this.textDirection, {
100 this.assertiveness = Assertiveness.polite,
101 }) : super('announce');
102
103 /// The message to announce.
104 final String message;
105
106 /// Text direction for [message].
107 final TextDirection textDirection;
108
109 /// Determines whether the announcement should interrupt any existing announcement,
110 /// or queue after it.
111 ///
112 /// On the web this option uses the aria-live level to set the assertiveness
113 /// of the announcement. On iOS, Android, Windows, Linux, macOS, and Fuchsia
114 /// this option currently has no effect.
115 final Assertiveness assertiveness;
116
117 @override
118 Map<String, dynamic> getDataMap() {
119 return <String, dynamic>{
120 'message': message,
121 'textDirection': textDirection.index,
122 if (assertiveness != Assertiveness.polite) 'assertiveness': assertiveness.index,
123 };
124 }
125}
126
127/// An event for a semantic announcement of a tooltip.
128///
129/// This is only used by Android to announce tooltip values.
130class TooltipSemanticsEvent extends SemanticsEvent {
131 /// Constructs an event that triggers a tooltip announcement by the platform.
132 const TooltipSemanticsEvent(this.message) : super('tooltip');
133
134 /// The text content of the tooltip.
135 final String message;
136
137 @override
138 Map<String, dynamic> getDataMap() {
139 return <String, dynamic>{'message': message};
140 }
141}
142
143/// An event which triggers long press semantic feedback.
144///
145/// Currently only honored on Android. Triggers a long-press specific sound
146/// when TalkBack is enabled.
147class LongPressSemanticsEvent extends SemanticsEvent {
148 /// Constructs an event that triggers a long-press semantic feedback by the platform.
149 const LongPressSemanticsEvent() : super('longPress');
150
151 @override
152 Map<String, dynamic> getDataMap() => const <String, dynamic>{};
153}
154
155/// An event which triggers tap semantic feedback.
156///
157/// Currently only honored on Android. Triggers a tap specific sound when
158/// TalkBack is enabled.
159class TapSemanticEvent extends SemanticsEvent {
160 /// Constructs an event that triggers a long-press semantic feedback by the platform.
161 const TapSemanticEvent() : super('tap');
162
163 @override
164 Map<String, dynamic> getDataMap() => const <String, dynamic>{};
165}
166
167/// An event to move the accessibility focus.
168///
169/// Using this API is generally not recommended, as it may break a users' expectation of
170/// how a11y focus works and therefore should be used very carefully.
171///
172/// One possible use case:
173/// For example, the currently focused rendering object is replaced by another rendering
174/// object. In general, such design should be avoided if possible. If not, one may want
175/// to refocus the newly added rendering object.
176///
177/// One example that is not recommended:
178/// When a new popup or dropdown opens, moving the focus in these cases may confuse users
179/// and make it less accessible.
180///
181/// {@tool snippet}
182///
183/// The following code snippet shows how one can request focus on a
184/// certain widget.
185///
186/// ```dart
187/// class MyWidget extends StatefulWidget {
188/// const MyWidget({super.key});
189///
190/// @override
191/// State<MyWidget> createState() => _MyWidgetState();
192/// }
193///
194/// class _MyWidgetState extends State<MyWidget> {
195/// final GlobalKey mykey = GlobalKey();
196///
197/// @override
198/// void initState() {
199/// super.initState();
200/// // Using addPostFrameCallback because changing focus need to wait for the widget to finish rendering.
201/// WidgetsBinding.instance.addPostFrameCallback((_) {
202/// mykey.currentContext?.findRenderObject()?.sendSemanticsEvent(const FocusSemanticEvent());
203/// });
204/// }
205///
206/// @override
207/// Widget build(BuildContext context) {
208/// return Scaffold(
209/// appBar: AppBar(
210/// title: const Text('example'),
211/// ),
212/// body: Column(
213/// children: <Widget>[
214/// const Text('Hello World'),
215/// const SizedBox(height: 50),
216/// Text('set focus here', key: mykey),
217/// ],
218/// ),
219/// );
220/// }
221/// }
222/// ```
223/// {@end-tool}
224///
225/// This currently only supports Android and iOS.
226class FocusSemanticEvent extends SemanticsEvent {
227 /// Constructs an event that triggers a focus change by the platform.
228 const FocusSemanticEvent() : super('focus');
229
230 @override
231 Map<String, dynamic> getDataMap() => const <String, dynamic>{};
232}
233

Provided by KDAB

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