flutter 3.44.0

Signed-off-by: dom <githubaccount56556@proton.me>
This commit is contained in:
dom
2026-05-16 22:51:33 +08:00
parent ad1583706a
commit 1fcc26464f
73 changed files with 1350 additions and 530 deletions

View File

@@ -2,13 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// ignore_for_file: prefer_initializing_formals
import 'dart:async';
import 'dart:math' as math;
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/material.dart' hide Slider;
import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart' show timeDilation;
import 'package:flutter/services.dart';
@@ -1019,6 +1021,7 @@ class _VerticalSliderState extends State<VerticalSlider>
onChangeEnd: _handleDragEnd,
state: this,
semanticFormatterCallback: widget.semanticFormatterCallback,
onDidGainAccessibilityFocus: handleDidGainAccessibilityFocus,
hasFocus: _focused,
hovering: _hovering,
allowedInteraction: effectiveAllowedInteraction,
@@ -1037,22 +1040,17 @@ class _VerticalSliderState extends State<VerticalSlider>
child: result,
);
return Semantics(
label: widget.label,
container: true,
slider: true,
onDidGainAccessibilityFocus: handleDidGainAccessibilityFocus,
child: FocusableActionDetector(
actions: _actionMap,
shortcuts: shortcutMap,
focusNode: focusNode,
autofocus: widget.autofocus,
enabled: _enabled,
onShowFocusHighlight: _handleFocusHighlightChanged,
onShowHoverHighlight: _handleHoverChanged,
mouseCursor: effectiveMouseCursor,
child: result,
),
return FocusableActionDetector(
actions: _actionMap,
shortcuts: shortcutMap,
focusNode: focusNode,
autofocus: widget.autofocus,
enabled: _enabled,
onShowFocusHighlight: _handleFocusHighlightChanged,
onShowHoverHighlight: _handleHoverChanged,
mouseCursor: effectiveMouseCursor,
includeFocusSemantics: false,
child: result,
);
}
@@ -1111,6 +1109,7 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget {
required this.onChangeEnd,
required this.state,
required this.semanticFormatterCallback,
required this.onDidGainAccessibilityFocus,
required this.hasFocus,
required this.hovering,
required this.allowedInteraction,
@@ -1127,6 +1126,7 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget {
final ValueChanged<double>? onChangeStart;
final ValueChanged<double>? onChangeEnd;
final SemanticFormatterCallback? semanticFormatterCallback;
final VoidCallback? onDidGainAccessibilityFocus;
final _VerticalSliderState state;
final bool hasFocus;
final bool hovering;
@@ -1148,6 +1148,7 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget {
state: state,
textDirection: Directionality.of(context),
semanticFormatterCallback: semanticFormatterCallback,
onDidGainAccessibilityFocus: onDidGainAccessibilityFocus,
platform: Theme.of(context).platform,
hasFocus: hasFocus,
hovering: hovering,
@@ -1173,6 +1174,7 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget {
..onChangeEnd = onChangeEnd
..textDirection = Directionality.of(context)
..semanticFormatterCallback = semanticFormatterCallback
..onDidGainAccessibilityFocus = onDidGainAccessibilityFocus
..platform = Theme.of(context).platform
..hasFocus = hasFocus
..hovering = hovering
@@ -1195,6 +1197,7 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
required TargetPlatform platform,
required ValueChanged<double>? onChanged,
required SemanticFormatterCallback? semanticFormatterCallback,
required this.onDidGainAccessibilityFocus,
required this.onChangeStart,
required this.onChangeEnd,
required _VerticalSliderState state,
@@ -1292,6 +1295,7 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
late VerticalDragGestureRecognizer _drag;
late TapGestureRecognizer _tap;
bool _active = false;
VoidCallback? onDidGainAccessibilityFocus;
double _currentDragValue = 0.0;
Rect? overlayRect;
@@ -1808,31 +1812,12 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
sliderTheme: _sliderTheme,
isDiscrete: isDiscrete,
);
final double padding = _sliderTheme.trackShape!.isRounded
? trackRect.width
: 0.0;
final double thumbPosition = isDiscrete
? trackRect.left +
visualPosition * (trackRect.width - padding) +
padding / 2
: trackRect.bottom - visualPosition * trackRect.height;
// Apply padding to trackRect.left and trackRect.right if the track height is
// greater than the thumb radius to ensure the thumb is drawn within the track.
final Size thumbPreferredSize = _sliderTheme.thumbShape!.getPreferredSize(
isInteractive,
isDiscrete,
);
final double thumbPadding = (padding > thumbPreferredSize.width / 2
? padding / 2
: 0);
final thumbCenter = Offset(
trackRect.center.dx,
clampDouble(
thumbPosition,
trackRect.top + thumbPadding,
trackRect.bottom - thumbPadding,
),
final Offset thumbCenter = _calcThumbCenter(
trackRect: trackRect,
visualPosition: visualPosition,
);
if (isInteractive) {
final Size overlaySize = sliderTheme.overlayShape!.getPreferredSize(
isInteractive,
@@ -1940,33 +1925,35 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
}
}
if (isInteractive && label != null) {
if ((shouldShowValueIndicatorWhenDragged &&
!_valueIndicatorAnimation.isDismissed) ||
shouldAlwaysShowValueIndicator) {
_state.paintValueIndicator = (PaintingContext context, Offset offset) {
if (attached && _labelPainter.text != null) {
_sliderTheme.valueIndicatorShape!.paint(
context,
offset + thumbCenter,
activationAnimation: shouldAlwaysShowValueIndicator
? const AlwaysStoppedAnimation<double>(1)
: _valueIndicatorAnimation,
enableAnimation: shouldAlwaysShowValueIndicator
? const AlwaysStoppedAnimation<double>(1)
: _enableAnimation,
isDiscrete: isDiscrete,
labelPainter: _labelPainter,
parentBox: this,
sliderTheme: _sliderTheme,
textDirection: _textDirection,
value: _value,
textScaleFactor: textScaleFactor,
sizeWithOverflow: screenSize.isEmpty ? size : screenSize,
);
}
};
}
if (isInteractive &&
label != null &&
((shouldShowValueIndicatorWhenDragged &&
!_valueIndicatorAnimation.isDismissed) ||
shouldAlwaysShowValueIndicator)) {
_state.paintValueIndicator = (PaintingContext context, Offset offset) {
if (attached && _labelPainter.text != null) {
_sliderTheme.valueIndicatorShape?.paint(
context,
offset + thumbCenter,
activationAnimation: shouldAlwaysShowValueIndicator
? const AlwaysStoppedAnimation<double>(1)
: _valueIndicatorAnimation,
enableAnimation: shouldAlwaysShowValueIndicator
? const AlwaysStoppedAnimation<double>(1)
: _enableAnimation,
isDiscrete: isDiscrete,
labelPainter: _labelPainter,
parentBox: this,
sliderTheme: _sliderTheme,
textDirection: _textDirection,
value: _value,
textScaleFactor: textScaleFactor,
sizeWithOverflow: screenSize.isEmpty ? size : screenSize,
);
}
};
} else {
_state.paintValueIndicator = null;
}
_sliderTheme.thumbShape!.paint(
@@ -1991,27 +1978,96 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
);
}
/// Calculates the local coordinate center of the [Slider] thumb given its
/// physical placement on the track from 0.0 (left) to 1.0 (right).
///
/// The [visualPosition] is provided by the caller so semantics can use the
/// raw logical value while paint can use the smoothly animated value.
Offset _calcThumbCenter({
required Rect trackRect,
required double visualPosition,
}) {
final double padding = _sliderTheme.trackShape!.isRounded
? trackRect.width
: 0.0;
final double thumbPosition = isDiscrete
? trackRect.left +
visualPosition * (trackRect.width - padding) +
padding / 2
: trackRect.bottom - visualPosition * trackRect.height;
// Apply padding to trackRect.left and trackRect.right if the track height is
// greater than the thumb radius to ensure the thumb is drawn within the track.
final Size thumbPreferredSize = _sliderTheme.thumbShape!.getPreferredSize(
isInteractive,
isDiscrete,
);
final double thumbPadding = padding > thumbPreferredSize.width / 2
? padding / 2
: 0;
return Offset(
trackRect.center.dx,
clampDouble(
thumbPosition,
trackRect.top + thumbPadding,
trackRect.bottom - thumbPadding,
),
);
}
Offset get _semanticThumbCenter {
final double visualPosition = switch (textDirection) {
TextDirection.rtl => 1.0 - _value,
TextDirection.ltr => _value,
};
return _calcThumbCenter(
trackRect: _trackRect,
visualPosition: visualPosition,
);
}
@override
void assembleSemanticsNode(
SemanticsNode node,
SemanticsConfiguration config,
Iterable<SemanticsNode> children,
) {
node
..rect = Rect.fromCenter(
center: _semanticThumbCenter,
width: kMinInteractiveDimension,
height: kMinInteractiveDimension,
)
..updateWith(config: config);
}
@override
void describeSemanticsConfiguration(SemanticsConfiguration config) {
super.describeSemanticsConfiguration(config);
// The Slider widget has its own Focus widget with semantics information,
// The Slider widget has its own Focus widget.
// We mark the Focus widget with "includeFocusSemantics: false"
// and we want that semantics node to collect the semantics information here
// so that it's all in the same node: otherwise Talkback sees that the node
// has focusable children, and it won't focus the Slider's Focus widget
// because it thinks the Focus widget's node doesn't have anything to say
// (which it doesn't, but this child does). Aggregating the semantic
// information into one node means that Talkback will recognize that it has
// something to say and focus it when it receives keyboard focus.
// (See https://github.com/flutter/flutter/issues/57038 for context).
// so that it's all in the same node.
config
..isSemanticBoundary = false
..isEnabled = isInteractive
..textDirection = textDirection;
..isSemanticBoundary = true
..isEnabled = isInteractive;
if (label != null) {
config.label = label!;
}
config
..isSlider = true
..isFocusable = isInteractive
..isFocused = hasFocus;
if (onDidGainAccessibilityFocus != null) {
config.onDidGainAccessibilityFocus = onDidGainAccessibilityFocus;
}
config.textDirection = textDirection;
if (isInteractive) {
config
..onIncrease = increaseAction
..onDecrease = decreaseAction;
..onDecrease = decreaseAction
..onFocus = onFocusAction;
}
if (semanticFormatterCallback != null) {
@@ -2036,6 +2092,17 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
double get _semanticActionUnit =>
divisions != null ? 1.0 / divisions! : _adjustmentUnit;
void onFocusAction() {
if (isInteractive) {
if (!_state.mounted) {
return;
}
if (!hasFocus) {
_state.focusNode.requestFocus();
}
}
}
void increaseAction() {
if (isInteractive) {
onChangeStart!(currentValue);