anchor.diff:  
     Performance get _performance => config.selection._performance;
   
  -  bool _indicatorRectIsValid = false;
  -
  -  // The performance's status change is our indication that the selection index has
  -  // changed. We don't start animating the _indicatorRect until after we've reset
  -  // _indicatorRect here.
  +  int get _tabCount => config.labels.length;
  +
  +  bool _indexIsChanging = false;
  +
     void _handleStatusChange(PerformanceStatus status) {
  -    _indicatorRectIsValid = status == PerformanceStatus.forward;
  -    if (status == PerformanceStatus.forward) {
  +    if (_tabCount == 0)
  +      return;
  +
  +    if (_indexIsChanging && status == PerformanceStatus.completed) {
  +      _indexIsChanging = false;
  +      double progress = 0.5;
  +      if (config.selection.index == 0)
  +        progress = 0.0;
  +      else if (config.selection.index == _tabCount - 1)
  +        progress = 1.0;
  +      setState(() {
  +        _indicatorRect
  +          ..begin = _tabIndicatorRect(math.max(0, config.selection.index - 1))
  +          ..end = _tabIndicatorRect(math.min(_tabCount - 1, config.selection.index + 1))
  +          ..curve = null
  +          ..setProgress(progress, AnimationDirection.forward);
  +      });
  +    }
  +  }
  +
  +  void _handleProgressChange() {
  +    if (_tabCount == 0)
  +      return;
  +
  +    if (!_indexIsChanging && config.selection.indexIsChanging) {
         if (config.isScrollable)
           scrollTo(_centeredTabScrollOffset(config.selection.index), duration: _kTabBarScroll);
  -      setState(() {
  -        _indicatorRect
  -          ..begin = _indicatorRect.value ?? _tabIndicatorRect(config.selection.previousIndex)
  -          ..end = _tabIndicatorRect(config.selection.index);
  -      });
  -    }
  -  }
  -
  -  void _handleProgressChange() {
  -    // Performance listeners are notified before statusListeners.
  -    if (_indicatorRectIsValid && _performance.status == PerformanceStatus.forward) {
  -      setState(() {
  -        _indicatorRect.setProgress(_performance.progress, AnimationDirection.forward);
  -      });
  -    }
  +      _indicatorRect
  +        ..begin = _indicatorRect.value ?? _tabIndicatorRect(config.selection.previousIndex)
  +        ..end = _tabIndicatorRect(config.selection.index)
  +        ..curve = Curves.ease;
  +      _indexIsChanging = true;
  +    }
  +    setState(() {
  +      _indicatorRect.setProgress(_performance.progress, AnimationDirection.forward);
  +    });
     }
   
     Size _viewportSize = Size.zero;
     Size _tabBarSize;
     List<double> _tabWidths;
  -  AnimatedRectValue _indicatorRect = new AnimatedRectValue(null, curve: Curves.ease);
  +  AnimatedRectValue _indicatorRect = new AnimatedRectValue(null);
   
     Rect _tabRect(int tabIndex) {
       assert(_tabBarSize != null);
  
positive.code: // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  import 'dart:math' as math;
  
  import 'package:newton/newton.dart';
  
negative.code:       .map((int i) => config.itemBuilder(context, config.items[i], i))
        .toList();
    }
  
    void dispatchOnScroll() {
      if (config.selection.indexIsChanging)
        return;
      // This class is driving the TabBarSelection's performance.
  
      if (config.selection.index == 0 || config.selection.index == _tabCount - 1)
        _performance.progress = scrollOffset;
      else
        _performance.progress = scrollOffset / 2.0;
    }
  
    Future fling(Offset scrollVelocity) {
      // TODO(hansmuller): should not short-circuit in this case.
      if (config.selection.indexIsChanging)
        return new Future.value();
  
      if (scrollVelocity != Offset.zero) {
        final int selectionDelta = scrollVelocity.dx > 0 ? -1 : 1;
        config.selection.index = (config.selection.index + selectionDelta).clamp(0, _tabCount - 1);
        return new Future.value();
      }
  
      final int selectionIndex = config.selection.index;
      final int settleIndex = snapScrollOffset(scrollOffset).toInt();
      if (selectionIndex > 0 && settleIndex != 1) {
          config.selection.index += settleIndex == 2 ? 1 : -1;
          return new Future.value();
      } else if (selectionIndex == 0 && settleIndex == 1) {
        config.selection.index = 1;
        return new Future.value();
      }
      return settleScrollOffset();
    }
  
  }
  