@@ -821,22 +821,11 @@ class _SliderState extends State<Slider> with TickerProviderStateMixin {
821821 // in range_slider.dart.
822822 Size screenSize () => MediaQuery .of (context).size;
823823
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+ }
840829 }
841830
842831 final Map <ShortcutActivator , Intent > shortcutMap;
@@ -857,38 +846,35 @@ class _SliderState extends State<Slider> with TickerProviderStateMixin {
857846 ? math.min (MediaQuery .of (context).textScaleFactor, 1.3 )
858847 : MediaQuery .of (context).textScaleFactor;
859848
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,
892878 ),
893879 ),
894880 );
@@ -949,6 +935,7 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget {
949935 required this .onChangeEnd,
950936 required this .state,
951937 required this .semanticFormatterCallback,
938+ required this .onDidGainAccessibilityFocus,
952939 required this .hasFocus,
953940 required this .hovering,
954941 });
@@ -964,6 +951,7 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget {
964951 final ValueChanged <double >? onChangeStart;
965952 final ValueChanged <double >? onChangeEnd;
966953 final SemanticFormatterCallback ? semanticFormatterCallback;
954+ final VoidCallback ? onDidGainAccessibilityFocus;
967955 final _SliderState state;
968956 final bool hasFocus;
969957 final bool hovering;
@@ -984,6 +972,7 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget {
984972 state: state,
985973 textDirection: Directionality .of (context),
986974 semanticFormatterCallback: semanticFormatterCallback,
975+ onDidGainAccessibilityFocus: onDidGainAccessibilityFocus,
987976 platform: Theme .of (context).platform,
988977 hasFocus: hasFocus,
989978 hovering: hovering,
@@ -1008,6 +997,7 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget {
1008997 ..onChangeEnd = onChangeEnd
1009998 ..textDirection = Directionality .of (context)
1010999 ..semanticFormatterCallback = semanticFormatterCallback
1000+ ..onDidGainAccessibilityFocus = onDidGainAccessibilityFocus
10111001 ..platform = Theme .of (context).platform
10121002 ..hasFocus = hasFocus
10131003 ..hovering = hovering
@@ -1029,6 +1019,7 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
10291019 required TargetPlatform platform,
10301020 required ValueChanged <double >? onChanged,
10311021 required SemanticFormatterCallback ? semanticFormatterCallback,
1022+ required this .onDidGainAccessibilityFocus,
10321023 required this .onChangeStart,
10331024 required this .onChangeEnd,
10341025 required _SliderState state,
@@ -1114,6 +1105,7 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
11141105 bool _active = false ;
11151106 double _currentDragValue = 0.0 ;
11161107 Rect ? overlayRect;
1108+ late Offset _thumbCenter;
11171109
11181110 // This rect is used in gesture calculations, where the gesture coordinates
11191111 // are relative to the sliders origin. Therefore, the offset is passed as
@@ -1259,6 +1251,7 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
12591251 }
12601252 }
12611253
1254+ VoidCallback ? onDidGainAccessibilityFocus;
12621255 ValueChanged <double >? onChangeStart;
12631256 ValueChanged <double >? onChangeEnd;
12641257
@@ -1582,10 +1575,10 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
15821575 sliderTheme: _sliderTheme,
15831576 isDiscrete: isDiscrete,
15841577 );
1585- final Offset thumbCenter = Offset (trackRect.left + visualPosition * trackRect.width, trackRect.center.dy);
1578+ _thumbCenter = Offset (trackRect.left + visualPosition * trackRect.width, trackRect.center.dy);
15861579 if (isInteractive) {
15871580 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 );
15891582 }
15901583 final Offset ? secondaryOffset = (secondaryVisualPosition != null ) ? Offset (trackRect.left + secondaryVisualPosition * trackRect.width, trackRect.center.dy) : null ;
15911584
@@ -1596,7 +1589,7 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
15961589 sliderTheme: _sliderTheme,
15971590 enableAnimation: _enableAnimation,
15981591 textDirection: _textDirection,
1599- thumbCenter: thumbCenter ,
1592+ thumbCenter: _thumbCenter ,
16001593 secondaryOffset: secondaryOffset,
16011594 isDiscrete: isDiscrete,
16021595 isEnabled: isInteractive,
@@ -1605,7 +1598,7 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
16051598 if (! _overlayAnimation.isDismissed) {
16061599 _sliderTheme.overlayShape! .paint (
16071600 context,
1608- thumbCenter ,
1601+ _thumbCenter ,
16091602 activationAnimation: _overlayAnimation,
16101603 enableAnimation: _enableAnimation,
16111604 isDiscrete: isDiscrete,
@@ -1642,7 +1635,7 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
16421635 sliderTheme: _sliderTheme,
16431636 enableAnimation: _enableAnimation,
16441637 textDirection: _textDirection,
1645- thumbCenter: thumbCenter ,
1638+ thumbCenter: _thumbCenter ,
16461639 isEnabled: isInteractive,
16471640 );
16481641 }
@@ -1655,7 +1648,7 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
16551648 if (attached) {
16561649 _sliderTheme.valueIndicatorShape! .paint (
16571650 context,
1658- offset + thumbCenter ,
1651+ offset + _thumbCenter ,
16591652 activationAnimation: _valueIndicatorAnimation,
16601653 enableAnimation: _enableAnimation,
16611654 isDiscrete: isDiscrete,
@@ -1674,7 +1667,7 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
16741667
16751668 _sliderTheme.thumbShape! .paint (
16761669 context,
1677- thumbCenter ,
1670+ _thumbCenter ,
16781671 activationAnimation: _overlayAnimation,
16791672 enableAnimation: _enableAnimation,
16801673 isDiscrete: isDiscrete,
@@ -1688,22 +1681,47 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
16881681 );
16891682 }
16901683
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+
16911695 @override
16921696 void describeSemanticsConfiguration (SemanticsConfiguration config) {
16931697 super .describeSemanticsConfiguration (config);
16941698
16951699 // 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
16971701 // so that it's all in the same node: otherwise Talkback sees that the node
16981702 // has focusable children, and it won't focus the Slider's Focus widget
16991703 // because it thinks the Focus widget's node doesn't have anything to say
17001704 // (which it doesn't, but this child does). Aggregating the semantic
17011705 // information into one node means that Talkback will recognize that it has
17021706 // something to say and focus it when it receives keyboard focus.
17031707 // (See https://github.com/flutter/flutter/issues/57038 for context).
1704- config.isSemanticBoundary = false ;
1708+ config.isSemanticBoundary = true ;
17051709
17061710 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+ }
17071725 config.textDirection = textDirection;
17081726 if (isInteractive) {
17091727 config.onIncrease = increaseAction;
0 commit comments