@@ -308,6 +308,72 @@ class PlatformDispatcher {
308
308
_invoke (onMetricsChanged, _onMetricsChangedZone);
309
309
}
310
310
311
+ /// A callback invoked immediately after the focus is transitioned across [FlutterView] s.
312
+ ///
313
+ /// When the platform moves the focus from one [FlutterView] to another, this
314
+ /// callback is invoked indicating the new view that has focus and the direction
315
+ /// in which focus was received. For example, if focus is moved to the [FlutterView]
316
+ /// with ID 2 in the forward direction (could be the result of pressing tab)
317
+ /// the callback receives a [ViewFocusEvent] with [ViewFocusState.focused] and
318
+ /// [ViewFocusDirection.forward] .
319
+ ///
320
+ /// Typically, receivers of this event respond by moving the focus to the first
321
+ /// focusable widget inside the [FlutterView] with ID 2. If a view receives
322
+ /// focus in the backwards direction (could be the result of pressing shift + tab),
323
+ /// typically the last focusable widget inside that view is focused.
324
+ ///
325
+ /// The platform may remove focus from a [FlutterView] . For example, on the web,
326
+ /// the browser can move focus to another element, or to the browser's built-in UI.
327
+ /// On desktop, the operating system can switch to another window (e.g. using Alt + Tab on Windows).
328
+ /// In scenarios like these, [onViewFocusChange] will be invoked with [ViewFocusState.unfocused] and
329
+ /// [ViewFocusDirection.undefined] .
330
+ ///
331
+ /// Receivers typically respond to this event by removing all focus indications
332
+ /// from the app.
333
+ ///
334
+ /// Apps can also programmatically request to move the focus to a desired
335
+ /// [FlutterView] by calling [requestViewFocusChange] .
336
+ ///
337
+ /// The callback is invoked in the same zone in which the callback was set.
338
+ ///
339
+ /// See also:
340
+ ///
341
+ /// * [requestViewFocusChange] to programmatically instruct the platform to move focus to a different [FlutterView] .
342
+ /// * [ViewFocusState] for a list of allowed focus transitions.
343
+ /// * [ViewFocusDirection] for a list of allowed focus directions.
344
+ /// * [ViewFocusEvent] , which is the event object provided to the callback.
345
+ ViewFocusChangeCallback ? get onViewFocusChange => _onViewFocusChange;
346
+ ViewFocusChangeCallback ? _onViewFocusChange;
347
+ // ignore: unused_field, field will be used when platforms other than web use these focus APIs.
348
+ Zone _onViewFocusChangeZone = Zone .root;
349
+ set onViewFocusChange (ViewFocusChangeCallback ? callback) {
350
+ _onViewFocusChange = callback;
351
+ _onViewFocusChangeZone = Zone .current;
352
+ }
353
+
354
+ /// Requests a focus change of the [FlutterView] with ID [viewId] .
355
+ ///
356
+ /// If an app would like to request the engine to move focus, in forward direction,
357
+ /// to the [FlutterView] with ID 1 it should call this method with [ViewFocusState.focused]
358
+ /// and [ViewFocusDirection.forward] .
359
+ ///
360
+ /// There is no need to call this method if the view in question already has
361
+ /// focus as it won't have any effect.
362
+ ///
363
+ /// A call to this method will lead to the engine calling [onViewFocusChange]
364
+ /// if the request is successfully fulfilled.
365
+ ///
366
+ /// See also:
367
+ ///
368
+ /// * [onViewFocusChange] , a callback to subscribe to view focus change events.
369
+ void requestViewFocusChange ({
370
+ required int viewId,
371
+ required ViewFocusState state,
372
+ required ViewFocusDirection direction,
373
+ }) {
374
+ // TODO(tugorez): implement this method. At the moment will be a no op call.
375
+ }
376
+
311
377
/// A callback invoked when any view begins a frame.
312
378
///
313
379
/// A callback that is invoked to notify the application that it is an
@@ -2552,3 +2618,80 @@ class SemanticsActionEvent {
2552
2618
);
2553
2619
}
2554
2620
}
2621
+
2622
+ /// Signature for [PlatformDispatcher.onViewFocusChange] .
2623
+ typedef ViewFocusChangeCallback = void Function (ViewFocusEvent viewFocusEvent);
2624
+
2625
+ /// An event for the engine to communicate view focus changes to the app.
2626
+ ///
2627
+ /// This value will be typically passed to the [PlatformDispatcher.onViewFocusChange]
2628
+ /// callback.
2629
+ final class ViewFocusEvent {
2630
+ /// Creates a [ViewFocusChange] .
2631
+ const ViewFocusEvent ({
2632
+ required this .viewId,
2633
+ required this .state,
2634
+ required this .direction,
2635
+ });
2636
+
2637
+ /// The ID of the [FlutterView] that experienced a focus change.
2638
+ final int viewId;
2639
+
2640
+ /// The state focus changed to.
2641
+ final ViewFocusState state;
2642
+
2643
+ /// The direction focus changed to.
2644
+ final ViewFocusDirection direction;
2645
+
2646
+ @override
2647
+ String toString () {
2648
+ return 'ViewFocusEvent(viewId: $viewId , state: $state , direction: $direction )' ;
2649
+ }
2650
+ }
2651
+
2652
+ /// Represents the focus state of a given [FlutterView] .
2653
+ ///
2654
+ /// When focus is lost, the view's focus state changes to [ViewFocusState.unfocused] .
2655
+ ///
2656
+ /// When focus is gained, the view's focus state changes to [ViewFocusState.focused] .
2657
+ ///
2658
+ /// Valid transitions within a view are:
2659
+ ///
2660
+ /// - [ViewFocusState.focused] to [ViewFocusState.unfocused] .
2661
+ /// - [ViewFocusState.unfocused] to [ViewFocusState.focused] .
2662
+ ///
2663
+ /// See also:
2664
+ ///
2665
+ /// * [ViewFocusDirection] , that specifies the focus direction.
2666
+ /// * [ViewFocusEvent] , that conveys information about a [FlutterView] focus change.
2667
+ enum ViewFocusState {
2668
+ /// Specifies that a view does not have platform focus.
2669
+ unfocused,
2670
+
2671
+ /// Specifies that a view has platform focus.
2672
+ focused,
2673
+ }
2674
+
2675
+ /// Represents the direction in which the focus transitioned across [FlutterView] s.
2676
+ ///
2677
+ /// See also:
2678
+ ///
2679
+ /// * [ViewFocusState] , that specifies the current focus state of a [FlutterView] .
2680
+ /// * [ViewFocusEvent] , that conveys information about a [FlutterView] focus change.
2681
+ enum ViewFocusDirection {
2682
+ /// Indicates the focus transition did not have a direction.
2683
+ ///
2684
+ /// This is typically associated with focus being programmatically requested or
2685
+ /// when focus is lost.
2686
+ undefined,
2687
+
2688
+ /// Indicates the focus transition was performed in a forward direction.
2689
+ ///
2690
+ /// This is typically result of the user pressing tab.
2691
+ forward,
2692
+
2693
+ /// Indicates the focus transition was performed in a backwards direction.
2694
+ ///
2695
+ /// This is typically result of the user pressing shift + tab.
2696
+ backwards,
2697
+ }
0 commit comments