Skip to content

Commit

Permalink
fix animateTo bug when new index > 1 tab away
Browse files Browse the repository at this point in the history
  • Loading branch information
qixotic committed Aug 1, 2022
1 parent 439d55e commit 4cdabb8
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 38 deletions.
17 changes: 10 additions & 7 deletions example/lib/default_appbar_demo.dart
Original file line number Diff line number Diff line change
Expand Up @@ -163,11 +163,12 @@ class _State extends State<DefaultAppBarDemo>
color: Colors.white,
tooltip: "convex button example",
onPressed: () => Navigator.of(context).pushNamed('/fab'),
), IconButton(
icon: Icon(Icons.radio_button_checked),
),
IconButton(
icon: Icon(Icons.looks_two),
color: Colors.white,
tooltip: "change tab by controller",
onPressed: (){
onPressed: () {
_tabController?.animateTo(2);
},
)
Expand Down Expand Up @@ -195,7 +196,11 @@ class _State extends State<DefaultAppBarDemo>
onTap: (int i) => debugPrint('select index=$i'),
)
: ConvexAppBar.badge(
{3: _badge!.text, 4: Icons.assistant_photo, 2: Colors.redAccent},
{
3: _badge!.text,
4: Icons.assistant_photo,
2: Colors.redAccent
},
badgePadding: _badge!.padding,
badgeColor: _badge!.badgeColor,
badgeBorderRadius: _badge!.borderRadius,
Expand All @@ -221,9 +226,7 @@ class _State extends State<DefaultAppBarDemo>
});
}

void _onNothing(ChoiceValue<TabStyle>? value) {

}
void _onNothing(ChoiceValue<TabStyle>? value) {}

void _onStyleChanged(ChoiceValue<TabStyle>? value) {
if (value == null) {
Expand Down
35 changes: 19 additions & 16 deletions lib/src/bar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ class ConvexAppBar extends StatefulWidget {
class ConvexAppBarState extends State<ConvexAppBar>
with TickerProviderStateMixin {
int? _currentIndex;
int? get currentIndex => _currentIndex;
int _warpUnderwayCount = 0;
Animation<double>? _animation;
AnimationController? _animationController;
Expand Down Expand Up @@ -403,17 +404,14 @@ class ConvexAppBarState extends State<ConvexAppBar>
if (c == null) {
return;
}
// Workaround for TabController, see https://github.com/hacktons/convex_bottom_bar/issues/59
var _diff = (c.index - _currentIndex!).abs();
if (_diff == 1) {
if (_blockEvent(c.index)) return;
final previousIndex = c.previousIndex;
final index = c.index;
_warpUnderwayCount += 1;
await animateTo(index, from: previousIndex);
_warpUnderwayCount -= 1;
return Future<void>.value();
}
if (_blockEvent(c.index)) return;
final previousIndex = c.previousIndex;
final index = c.index;
// Counter to avoid repeat calls to animateTo in the middle of a transition.
_warpUnderwayCount += 1;
await animateTo(index, from: previousIndex);
_warpUnderwayCount -= 1;
return Future<void>.value();
}

/// change active tab index; can be used with [PageView].
Expand Down Expand Up @@ -465,15 +463,15 @@ class ConvexAppBarState extends State<ConvexAppBar>
super.dispose();
}

TabController? get _takeControllerRef {
TabController? get _currentControllerRef {
if (widget.disableDefaultTabController == true) {
return widget.controller;
}
return widget.controller ?? DefaultTabController.of(context);
}

void _updateTabController() {
final newController = _takeControllerRef;
final newController = _currentControllerRef;
assert(() {
if (newController != null &&
widget.controller == null &&
Expand Down Expand Up @@ -505,7 +503,7 @@ class ConvexAppBarState extends State<ConvexAppBar>
@override
void didChangeDependencies() {
super.didChangeDependencies();
if (_controller != _takeControllerRef) {
if (_controller != _currentControllerRef) {
_updateTabController();
_resetState();
}
Expand Down Expand Up @@ -625,8 +623,13 @@ class ConvexAppBarState extends State<ConvexAppBar>

void _onTabClick(int i) {
if (_blockEvent(i)) return;
animateTo(i);
_controller?.animateTo(i);
if (_controller == null) {
animateTo(i);
} else {
// animation listener [_handleTabControllerAnimationTick] will drive the
// internal animateTo() via [_warpToCurrentIndex].
_controller!.animateTo(i);
}
widget.onTap?.call(i);
}

Expand Down
67 changes: 52 additions & 15 deletions test/widget_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -188,39 +188,70 @@ void main() {
testWidgets('Test tab controller', (WidgetTester tester) async {
var controller =
TabController(length: 3, vsync: TestVSync(), initialIndex: 2);
var key = GlobalKey(debugLabel: 'appbar');
var key = GlobalKey<ConvexAppBarState>(debugLabel: 'appbar');
var appbar = ConvexAppBar.builder(
key: key,
controller: controller,
itemBuilder: Builder(),
count: 3,
top: -20,
onTap: (i) {
assert(i == 1);
expect(i, 1);
},
);
await tester.pumpWidget(
material(appbar),
// material(appbar),
material(Scaffold(
body: TabBarView(
controller: controller,
children: const <Widget>[
Center(child: Text('CHILD 0')),
Center(child: Text('CHILD 1')),
Center(child: Text('CHILD 2')),
],
),
bottomNavigationBar: appbar,
)),
Duration(milliseconds: 300),
);
expect(key.currentState?.currentIndex, 2);
expect(find.text('TAB 0'), findsOneWidget);
expect(find.text('TAB 1'), findsOneWidget);
expect(find.text('TAB 2'), findsOneWidget);
expect(find.text('CHILD 2'), findsOneWidget);

await tester.tap(find.text('TAB 1'));
await tester.tap(find.text('TAB 1'));
await tester.pumpAndSettle(Duration(milliseconds: 300));
await tester.startGesture(Offset(0, 100)).then((g) {
return g.moveTo(Offset(500, 100));
});
await tester.startGesture(Offset(0, 100)).then((g) {
return g.moveTo(Offset(100, 100));
});
controller.index = 1;
expect(controller.index, 1);
expect(key.currentState?.currentIndex, 1);

await tester.drag(find.text('CHILD 1'), Offset(1000, 0));
await tester.pumpAndSettle(Duration(milliseconds: 300));
expect(controller.index, 0);
expect(key.currentState?.currentIndex, 0);

controller.animateTo(2);
await tester.pumpAndSettle(Duration(milliseconds: 300));
expect(controller.index, 2);
expect(key.currentState?.currentIndex, 2);

// Test a custom controller accidentally used with the DefaultTabController
controller.index = 2;
await tester.pumpWidget(
material(DefaultTabController(
initialIndex: 2,
length: 3,
child: ConvexAppBar.builder(
initialIndex: 0,
length: 3,
child: material(Scaffold(
body: TabBarView(
controller: controller,
children: const <Widget>[
Center(child: Text('CHILD 0')),
Center(child: Text('CHILD 1')),
Center(child: Text('CHILD 2')),
],
),
bottomNavigationBar: ConvexAppBar.builder(
key: key,
controller: controller,
itemBuilder: Builder(),
Expand All @@ -229,10 +260,16 @@ void main() {
onTap: (i) {
assert(i == 1);
},
))),
),
)),
)),
Duration(milliseconds: 300),
);
controller.index = 1;
expect(key.currentState?.currentIndex, 2);
await tester.flingFrom(Offset(0, 100), const Offset(600, 100), 10000.0);
await tester.pumpAndSettle(Duration(milliseconds: 300));
expect(controller.index, 1);
expect(key.currentState?.currentIndex, 1);
});

testWidgets('Add badge on AppBar', (WidgetTester tester) async {
Expand Down

0 comments on commit 4cdabb8

Please sign in to comment.