@@ -821,22 +821,11 @@ class _SliderState extends State<Slider> with TickerProviderStateMixin {
821
821
// in range_slider.dart.
822
822
Size screenSize () => MediaQuery .of (context).size;
823
823
824
- VoidCallback ? handleDidGainAccessibilityFocus;
825
- switch (theme.platform) {
826
- case TargetPlatform .android:
827
- case TargetPlatform .fuchsia:
828
- case TargetPlatform .iOS:
829
- case TargetPlatform .linux:
830
- case TargetPlatform .macOS:
831
- break ;
832
- case TargetPlatform .windows:
833
- handleDidGainAccessibilityFocus = () {
834
- // Automatically activate the slider when it receives a11y focus.
835
- if (! focusNode.hasFocus && focusNode.canRequestFocus) {
836
- focusNode.requestFocus ();
837
- }
838
- };
839
- break ;
824
+ void handleDidGainAccessibilityFocus () {
825
+ // Automatically activate the slider when it receives a11y focus.
826
+ if (! focusNode.hasFocus && focusNode.canRequestFocus) {
827
+ focusNode.requestFocus ();
828
+ }
840
829
}
841
830
842
831
final Map <ShortcutActivator , Intent > shortcutMap;
@@ -857,38 +846,35 @@ class _SliderState extends State<Slider> with TickerProviderStateMixin {
857
846
? math.min (MediaQuery .of (context).textScaleFactor, 1.3 )
858
847
: MediaQuery .of (context).textScaleFactor;
859
848
860
- return Semantics (
861
- container: true ,
862
- slider: true ,
863
- onDidGainAccessibilityFocus: handleDidGainAccessibilityFocus,
864
- child: FocusableActionDetector (
865
- actions: _actionMap,
866
- shortcuts: shortcutMap,
867
- focusNode: focusNode,
868
- autofocus: widget.autofocus,
869
- enabled: _enabled,
870
- onShowFocusHighlight: _handleFocusHighlightChanged,
871
- onShowHoverHighlight: _handleHoverChanged,
872
- mouseCursor: effectiveMouseCursor,
873
- child: CompositedTransformTarget (
874
- link: _layerLink,
875
- child: _SliderRenderObjectWidget (
876
- key: _renderObjectKey,
877
- value: _convert (widget.value),
878
- secondaryTrackValue: (widget.secondaryTrackValue != null ) ? _convert (widget.secondaryTrackValue! ) : null ,
879
- divisions: widget.divisions,
880
- label: widget.label,
881
- sliderTheme: sliderTheme,
882
- textScaleFactor: textScaleFactor,
883
- screenSize: screenSize (),
884
- onChanged: (widget.onChanged != null ) && (widget.max > widget.min) ? _handleChanged : null ,
885
- onChangeStart: _handleDragStart,
886
- onChangeEnd: _handleDragEnd,
887
- state: this ,
888
- semanticFormatterCallback: widget.semanticFormatterCallback,
889
- hasFocus: _focused,
890
- hovering: _hovering,
891
- ),
849
+ return FocusableActionDetector (
850
+ actions: _actionMap,
851
+ shortcuts: shortcutMap,
852
+ focusNode: focusNode,
853
+ autofocus: widget.autofocus,
854
+ enabled: _enabled,
855
+ onShowFocusHighlight: _handleFocusHighlightChanged,
856
+ onShowHoverHighlight: _handleHoverChanged,
857
+ mouseCursor: effectiveMouseCursor,
858
+ includeFocusSemantics: false ,
859
+ child: CompositedTransformTarget (
860
+ link: _layerLink,
861
+ child: _SliderRenderObjectWidget (
862
+ key: _renderObjectKey,
863
+ value: _convert (widget.value),
864
+ secondaryTrackValue: (widget.secondaryTrackValue != null ) ? _convert (widget.secondaryTrackValue! ) : null ,
865
+ divisions: widget.divisions,
866
+ label: widget.label,
867
+ sliderTheme: sliderTheme,
868
+ textScaleFactor: textScaleFactor,
869
+ screenSize: screenSize (),
870
+ onChanged: (widget.onChanged != null ) && (widget.max > widget.min) ? _handleChanged : null ,
871
+ onChangeStart: _handleDragStart,
872
+ onChangeEnd: _handleDragEnd,
873
+ state: this ,
874
+ semanticFormatterCallback: widget.semanticFormatterCallback,
875
+ onDidGainAccessibilityFocus: handleDidGainAccessibilityFocus,
876
+ hasFocus: _focused,
877
+ hovering: _hovering,
892
878
),
893
879
),
894
880
);
@@ -949,6 +935,7 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget {
949
935
required this .onChangeEnd,
950
936
required this .state,
951
937
required this .semanticFormatterCallback,
938
+ required this .onDidGainAccessibilityFocus,
952
939
required this .hasFocus,
953
940
required this .hovering,
954
941
});
@@ -964,6 +951,7 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget {
964
951
final ValueChanged <double >? onChangeStart;
965
952
final ValueChanged <double >? onChangeEnd;
966
953
final SemanticFormatterCallback ? semanticFormatterCallback;
954
+ final VoidCallback ? onDidGainAccessibilityFocus;
967
955
final _SliderState state;
968
956
final bool hasFocus;
969
957
final bool hovering;
@@ -984,6 +972,7 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget {
984
972
state: state,
985
973
textDirection: Directionality .of (context),
986
974
semanticFormatterCallback: semanticFormatterCallback,
975
+ onDidGainAccessibilityFocus: onDidGainAccessibilityFocus,
987
976
platform: Theme .of (context).platform,
988
977
hasFocus: hasFocus,
989
978
hovering: hovering,
@@ -1008,6 +997,7 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget {
1008
997
..onChangeEnd = onChangeEnd
1009
998
..textDirection = Directionality .of (context)
1010
999
..semanticFormatterCallback = semanticFormatterCallback
1000
+ ..onDidGainAccessibilityFocus = onDidGainAccessibilityFocus
1011
1001
..platform = Theme .of (context).platform
1012
1002
..hasFocus = hasFocus
1013
1003
..hovering = hovering
@@ -1029,6 +1019,7 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
1029
1019
required TargetPlatform platform,
1030
1020
required ValueChanged <double >? onChanged,
1031
1021
required SemanticFormatterCallback ? semanticFormatterCallback,
1022
+ required this .onDidGainAccessibilityFocus,
1032
1023
required this .onChangeStart,
1033
1024
required this .onChangeEnd,
1034
1025
required _SliderState state,
@@ -1114,6 +1105,7 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
1114
1105
bool _active = false ;
1115
1106
double _currentDragValue = 0.0 ;
1116
1107
Rect ? overlayRect;
1108
+ late Offset _thumbCenter;
1117
1109
1118
1110
// This rect is used in gesture calculations, where the gesture coordinates
1119
1111
// are relative to the sliders origin. Therefore, the offset is passed as
@@ -1259,6 +1251,7 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
1259
1251
}
1260
1252
}
1261
1253
1254
+ VoidCallback ? onDidGainAccessibilityFocus;
1262
1255
ValueChanged <double >? onChangeStart;
1263
1256
ValueChanged <double >? onChangeEnd;
1264
1257
@@ -1582,10 +1575,10 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
1582
1575
sliderTheme: _sliderTheme,
1583
1576
isDiscrete: isDiscrete,
1584
1577
);
1585
- final Offset thumbCenter = Offset (trackRect.left + visualPosition * trackRect.width, trackRect.center.dy);
1578
+ _thumbCenter = Offset (trackRect.left + visualPosition * trackRect.width, trackRect.center.dy);
1586
1579
if (isInteractive) {
1587
1580
final Size overlaySize = sliderTheme.overlayShape! .getPreferredSize (isInteractive, false );
1588
- overlayRect = Rect .fromCircle (center: thumbCenter , radius: overlaySize.width / 2.0 );
1581
+ overlayRect = Rect .fromCircle (center: _thumbCenter , radius: overlaySize.width / 2.0 );
1589
1582
}
1590
1583
final Offset ? secondaryOffset = (secondaryVisualPosition != null ) ? Offset (trackRect.left + secondaryVisualPosition * trackRect.width, trackRect.center.dy) : null ;
1591
1584
@@ -1596,7 +1589,7 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
1596
1589
sliderTheme: _sliderTheme,
1597
1590
enableAnimation: _enableAnimation,
1598
1591
textDirection: _textDirection,
1599
- thumbCenter: thumbCenter ,
1592
+ thumbCenter: _thumbCenter ,
1600
1593
secondaryOffset: secondaryOffset,
1601
1594
isDiscrete: isDiscrete,
1602
1595
isEnabled: isInteractive,
@@ -1605,7 +1598,7 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
1605
1598
if (! _overlayAnimation.isDismissed) {
1606
1599
_sliderTheme.overlayShape! .paint (
1607
1600
context,
1608
- thumbCenter ,
1601
+ _thumbCenter ,
1609
1602
activationAnimation: _overlayAnimation,
1610
1603
enableAnimation: _enableAnimation,
1611
1604
isDiscrete: isDiscrete,
@@ -1642,7 +1635,7 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
1642
1635
sliderTheme: _sliderTheme,
1643
1636
enableAnimation: _enableAnimation,
1644
1637
textDirection: _textDirection,
1645
- thumbCenter: thumbCenter ,
1638
+ thumbCenter: _thumbCenter ,
1646
1639
isEnabled: isInteractive,
1647
1640
);
1648
1641
}
@@ -1655,7 +1648,7 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
1655
1648
if (attached) {
1656
1649
_sliderTheme.valueIndicatorShape! .paint (
1657
1650
context,
1658
- offset + thumbCenter ,
1651
+ offset + _thumbCenter ,
1659
1652
activationAnimation: _valueIndicatorAnimation,
1660
1653
enableAnimation: _enableAnimation,
1661
1654
isDiscrete: isDiscrete,
@@ -1674,7 +1667,7 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
1674
1667
1675
1668
_sliderTheme.thumbShape! .paint (
1676
1669
context,
1677
- thumbCenter ,
1670
+ _thumbCenter ,
1678
1671
activationAnimation: _overlayAnimation,
1679
1672
enableAnimation: _enableAnimation,
1680
1673
isDiscrete: isDiscrete,
@@ -1688,22 +1681,47 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
1688
1681
);
1689
1682
}
1690
1683
1684
+ @override
1685
+ void assembleSemanticsNode (SemanticsNode node, SemanticsConfiguration config, Iterable <SemanticsNode > children) {
1686
+ node.rect = Rect .fromCenter (
1687
+ center: _thumbCenter,
1688
+ width: kMinInteractiveDimension,
1689
+ height: kMinInteractiveDimension,
1690
+ );
1691
+
1692
+ node.updateWith (config: config);
1693
+ }
1694
+
1691
1695
@override
1692
1696
void describeSemanticsConfiguration (SemanticsConfiguration config) {
1693
1697
super .describeSemanticsConfiguration (config);
1694
1698
1695
1699
// The Slider widget has its own Focus widget with semantics information,
1696
- // and we want that semantics node to collect the semantics information here
1700
+ // and want that semantics node to collect the semantics information here
1697
1701
// so that it's all in the same node: otherwise Talkback sees that the node
1698
1702
// has focusable children, and it won't focus the Slider's Focus widget
1699
1703
// because it thinks the Focus widget's node doesn't have anything to say
1700
1704
// (which it doesn't, but this child does). Aggregating the semantic
1701
1705
// information into one node means that Talkback will recognize that it has
1702
1706
// something to say and focus it when it receives keyboard focus.
1703
1707
// (See https://github.com/flutter/flutter/issues/57038 for context).
1704
- config.isSemanticBoundary = false ;
1708
+ config.isSemanticBoundary = true ;
1705
1709
1706
1710
config.isEnabled = isInteractive;
1711
+ config.isSlider = true ;
1712
+ config.isFocusable = isInteractive;
1713
+ config.isFocused = hasFocus;
1714
+ switch (_platform) {
1715
+ case TargetPlatform .android:
1716
+ case TargetPlatform .fuchsia:
1717
+ case TargetPlatform .iOS:
1718
+ case TargetPlatform .linux:
1719
+ case TargetPlatform .macOS:
1720
+ break ;
1721
+ case TargetPlatform .windows:
1722
+ config.onDidGainAccessibilityFocus = onDidGainAccessibilityFocus;
1723
+ break ;
1724
+ }
1707
1725
config.textDirection = textDirection;
1708
1726
if (isInteractive) {
1709
1727
config.onIncrease = increaseAction;
0 commit comments