Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit df72eb9

Browse files
committed
Feat: Add momentary varient of CupertinoSlidingSegmentedControl
1 parent b924071 commit df72eb9

File tree

2 files changed

+68
-9
lines changed

2 files changed

+68
-9
lines changed

packages/flutter/lib/src/cupertino/sliding_segmented_control.dart

+42-9
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ const Radius _kSeparatorRadius = Radius.circular(_kSeparatorWidth / 2);
5252
// amount of time.
5353
const double _kMinThumbScale = 0.95;
5454

55+
// The maximum scale factor of the thumb, when being pressed on for a sufficient
56+
// amount of time.
57+
const double _kMaxThumbScale = 1.05;
58+
5559
// The minimum horizontal distance between the edges of the separator and the
5660
// closest child.
5761
const double _kSegmentMinPadding = 10;
@@ -104,6 +108,7 @@ class _Segment<T> extends StatefulWidget {
104108
required this.isDragging,
105109
required this.enabled,
106110
required this.segmentLocation,
111+
required this.isMomentary,
107112
}) : super(key: key);
108113

109114
final Widget child;
@@ -112,13 +117,15 @@ class _Segment<T> extends StatefulWidget {
112117
final bool highlighted;
113118
final bool enabled;
114119
final _SegmentLocation segmentLocation;
120+
final bool isMomentary;
115121

116122
// Whether the thumb of the parent widget (CupertinoSlidingSegmentedControl)
117123
// is currently being dragged.
118124
final bool isDragging;
119125

120-
bool get shouldFadeoutContent => pressed && !highlighted && enabled;
126+
bool get shouldFadeoutContent => pressed && !highlighted && enabled && !isMomentary;
121127
bool get shouldScaleContent => pressed && highlighted && isDragging && enabled;
128+
bool get shouldHighlightContent => highlighted && !isMomentary;
122129

123130
@override
124131
_SegmentState<T> createState() => _SegmentState<T>();
@@ -148,12 +155,26 @@ class _SegmentState<T> extends State<_Segment<T>> with TickerProviderStateMixin<
148155
assert(oldWidget.key == widget.key);
149156

150157
if (oldWidget.shouldScaleContent != widget.shouldScaleContent) {
151-
highlightPressScaleAnimation = highlightPressScaleController.drive(
152-
Tween<double>(
153-
begin: highlightPressScaleAnimation.value,
154-
end: widget.shouldScaleContent ? _kMinThumbScale : 1.0,
155-
),
156-
);
158+
final Animatable<double> scaleAnimation =
159+
widget.isMomentary && widget.shouldScaleContent
160+
? TweenSequence<double>(<TweenSequenceItem<double>>[
161+
TweenSequenceItem<double>(
162+
tween: Tween<double>(
163+
begin: highlightPressScaleAnimation.value,
164+
end: _kMaxThumbScale,
165+
),
166+
weight: 50,
167+
),
168+
TweenSequenceItem<double>(
169+
tween: Tween<double>(begin: _kMaxThumbScale, end: 1.0),
170+
weight: 50,
171+
),
172+
])
173+
: Tween<double>(
174+
begin: highlightPressScaleAnimation.value,
175+
end: widget.shouldScaleContent ? _kMinThumbScale : 1.0,
176+
);
177+
highlightPressScaleAnimation = highlightPressScaleController.drive(scaleAnimation);
157178
highlightPressScaleController.animateWith(_kThumbSpringAnimationSimulation);
158179
}
159180
}
@@ -185,7 +206,8 @@ class _SegmentState<T> extends State<_Segment<T>> with TickerProviderStateMixin<
185206
child: AnimatedDefaultTextStyle(
186207
style: DefaultTextStyle.of(context).style.merge(
187208
TextStyle(
188-
fontWeight: widget.highlighted ? _kHighlightedFontWeight : _kFontWeight,
209+
fontWeight:
210+
widget.shouldHighlightContent ? _kHighlightedFontWeight : _kFontWeight,
189211
fontSize: _kFontSize,
190212
color: widget.enabled ? null : _kDisabledContentColor,
191213
),
@@ -352,6 +374,7 @@ class CupertinoSlidingSegmentedControl<T extends Object> extends StatefulWidget
352374
this.padding = _kHorizontalItemPadding,
353375
this.backgroundColor = CupertinoColors.tertiarySystemFill,
354376
this.proportionalWidth = false,
377+
this.isMomentary = false,
355378
}) : assert(children.length >= 2),
356379
assert(
357380
groupValue == null || children.keys.contains(groupValue),
@@ -465,6 +488,14 @@ class CupertinoSlidingSegmentedControl<T extends Object> extends StatefulWidget
465488
/// Defaults to `EdgeInsets.symmetric(vertical: 2, horizontal: 3)`.
466489
final EdgeInsetsGeometry padding;
467490

491+
/// Determines whether segments in the segmented control show selected state.
492+
///
493+
/// If true, segments in the control don’t show selected state and
494+
/// don’t update the value of selectedSegmentIndex after tracking ends.
495+
///
496+
/// Defaults to false.
497+
final bool isMomentary;
498+
468499
@override
469500
State<CupertinoSlidingSegmentedControl<T>> createState() => _SegmentedControlState<T>();
470501
}
@@ -635,6 +666,7 @@ class _SegmentedControlState<T extends Object> extends State<CupertinoSlidingSeg
635666
if (isThumbDragging) {
636667
return;
637668
}
669+
638670
final T segment = segmentForXPosition(details.localPosition.dx);
639671
onPressedChangedByGesture(null);
640672
if (segment != widget.groupValue && !widget.disabledChildren.contains(segment)) {
@@ -769,6 +801,7 @@ class _SegmentedControlState<T extends Object> extends State<CupertinoSlidingSeg
769801
isDragging: isThumbDragging,
770802
enabled: !widget.disabledChildren.contains(entry.key),
771803
segmentLocation: segmentLocation,
804+
isMomentary: widget.isMomentary,
772805
child: entry.value,
773806
),
774807
),
@@ -807,7 +840,7 @@ class _SegmentedControlState<T extends Object> extends State<CupertinoSlidingSeg
807840
builder: (BuildContext context, Widget? child) {
808841
return _SegmentedControlRenderWidget<T>(
809842
key: segmentedControlRenderWidgetKey,
810-
highlightedIndex: highlightedIndex,
843+
highlightedIndex: widget.isMomentary ? null : highlightedIndex,
811844
thumbColor: CupertinoDynamicColor.resolve(widget.thumbColor, context),
812845
thumbScale: thumbScaleAnimation.value,
813846
proportionalWidth: widget.proportionalWidth,

packages/flutter/test/cupertino/sliding_segmented_control_test.dart

+26
Original file line numberDiff line numberDiff line change
@@ -2126,4 +2126,30 @@ void main() {
21262126

21272127
expect(onValueChangedCalled, 0);
21282128
});
2129+
2130+
testWidgets('CupertinoSlidingSegmentedControl can be momentary', (WidgetTester tester) async {
2131+
const Map<int, Widget> children = <int, Widget>{0: Text('A'), 1: Text('BB'), 2: Text('CCCC')};
2132+
2133+
groupValue = 1;
2134+
await tester.pumpWidget(
2135+
boilerplate(
2136+
builder: (BuildContext context) {
2137+
return CupertinoSlidingSegmentedControl<int>(
2138+
isMomentary: true,
2139+
children: children,
2140+
groupValue: groupValue,
2141+
onValueChanged: defaultCallback,
2142+
);
2143+
},
2144+
),
2145+
);
2146+
2147+
expect(getHighlightedIndex(tester), null);
2148+
2149+
// Tap first segment.
2150+
await tester.tap(find.text('A'));
2151+
await tester.pumpAndSettle();
2152+
2153+
expect(getHighlightedIndex(tester), null); // The highlighted index doesn't change
2154+
});
21292155
}

0 commit comments

Comments
 (0)