@@ -554,7 +554,7 @@ class _IndicatorPainter extends CustomPainter {
554
554
_currentRect = Rect .lerp (fromRect, toRect, (value - from).abs ());
555
555
556
556
_currentRect = switch (indicatorSize) {
557
- TabBarIndicatorSize .label => _applyStretchEffect (_currentRect! ),
557
+ TabBarIndicatorSize .label => _applyStretchEffect (_currentRect! , fromRect ),
558
558
// Do nothing.
559
559
TabBarIndicatorSize .tab => _currentRect,
560
560
};
@@ -575,8 +575,18 @@ class _IndicatorPainter extends CustomPainter {
575
575
_painter! .paint (canvas, _currentRect! .topLeft, configuration);
576
576
}
577
577
578
+ // Ease out sine (decelerating).
579
+ double decelerateInterpolation (double fraction) {
580
+ return math.sin ((fraction * math.pi) / 2.0 );
581
+ }
582
+
583
+ // Ease in sine (accelerating).
584
+ double accelerateInterpolation (double fraction) {
585
+ return 1.0 - math.cos ((fraction * math.pi) / 2.0 );
586
+ }
587
+
578
588
/// Applies the stretch effect to the indicator.
579
- Rect _applyStretchEffect (Rect rect) {
589
+ Rect _applyStretchEffect (Rect rect, Rect targetRect ) {
580
590
// If the tab animation is completed, there is no need to stretch the indicator
581
591
// This only works for the tab change animation via tab index, not when
582
592
// dragging a [TabBarView], but it's still ok, to avoid unnecessary calculations.
@@ -586,57 +596,30 @@ class _IndicatorPainter extends CustomPainter {
586
596
587
597
final double index = controller.index.toDouble ();
588
598
final double value = controller.animation! .value;
589
-
590
- // The progress of the animation from 0 to 1.
591
- late double tabChangeProgress;
592
-
593
- // If we are changing tabs via index, we want to map the progress between 0 and 1.
594
- if (controller.indexIsChanging) {
595
- double progressLeft = (index - value).abs ();
596
- final int tabsDelta = (controller.index - controller.previousIndex).abs ();
597
- if (tabsDelta != 0 ) {
598
- progressLeft /= tabsDelta;
599
- }
600
- tabChangeProgress = 1 - clampDouble (progressLeft, 0.0 , 1.0 );
601
- } else {
602
- // Otherwise, the progress is how close we are to the current tab.
603
- tabChangeProgress = (index - value).abs ();
604
- }
599
+ final double tabChangeProgress = (index - value).abs ();
605
600
606
601
// If the animation has finished, there is no need to apply the stretch effect.
607
602
if (tabChangeProgress == 1.0 ) {
608
603
return rect;
609
604
}
610
605
611
- // The maximum amount of extra width to add to the indicator.
612
- final double stretchSize = rect.width;
606
+ final double fraction = switch (rect.left < targetRect.left) {
607
+ true => accelerateInterpolation (tabChangeProgress),
608
+ false => decelerateInterpolation (tabChangeProgress),
609
+ };
613
610
614
- final double inflationPerSide = stretchSize * _stretchAnimation.transform (tabChangeProgress) / 2 ;
615
- final Rect stretchedRect = _inflateRectHorizontally (rect, inflationPerSide);
611
+ final Rect stretchedRect = _inflateRectHorizontally (rect, targetRect, fraction);
616
612
return stretchedRect;
617
613
}
618
614
619
- /// The animatable that stretches the indicator horizontally when changing tabs.
620
- /// Value range is from 0 to 1, so we can multiply it by an stretch factor.
621
- ///
622
- /// Animation starts with no stretch, then quickly goes to the max stretch amount
623
- /// and then goes back to no stretch.
624
- late final Animatable <double > _stretchAnimation = TweenSequence <double >(
625
- < TweenSequenceItem <double >> [
626
- TweenSequenceItem <double >(
627
- tween: Tween <double >(begin: 0.0 , end: 1.0 ),
628
- weight: 20 ,
629
- ),
630
- TweenSequenceItem <double >(
631
- tween: Tween <double >(begin: 1.0 , end: 0.0 ),
632
- weight: 80 ,
633
- ),
634
- ],
635
- );
636
-
637
615
/// Same as [Rect.inflate] , but only inflates in the horizontal direction.
638
- Rect _inflateRectHorizontally (Rect r, double delta) {
639
- return Rect .fromLTRB (r.left - delta, r.top, r.right + delta, r.bottom);
616
+ Rect _inflateRectHorizontally (Rect rect, Rect targetRect, double fraction) {
617
+ return Rect .fromLTRB (
618
+ lerpDouble (rect.left, targetRect.left, fraction)! ,
619
+ rect.top,
620
+ lerpDouble (rect.right, targetRect.right, fraction)! ,
621
+ rect.bottom,
622
+ );
640
623
}
641
624
642
625
@override
0 commit comments