Closed LiveLikeCounter closed 5 years ago
thanks, In order to do this it's necessary to add some kind of ScrollController to widget. It's important feature
Hi, sorry, dumb question but is this how one would make it swipable? I mean, the bottom bar successfully changes index if someone swipes but it also seems like it significantly lags behind the swipe action. Not sure if it's just the emulator though or I'm messing up with the addListener
or something else.
class HomePage extends StatefulWidget {
const HomePage({Key key}) : super(key: key);
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage>
with SingleTickerProviderStateMixin {
final List<Widget> _tabs = <Widget>[
/* tabs */
];
TabController _controller;
int _currentIndex = 0;
@override
void initState() {
super.initState();
_controller = TabController(
vsync: this,
length: _tabs.length,
initialIndex: 0,
);
_controller.addListener(() {
setState(() {
_currentIndex = _controller.index;
});
});
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
extendBody: true,
body: TabBarView(
controller: _controller,
children: _tabs.map<Widget>((Widget tab) {
return SafeArea(
top: false,
bottom: false,
child: Container(
key: ObjectKey(tab),
child: tab,
),
);
}).toList()),
bottomNavigationBar: CurvedNavigationBar(
index: _currentIndex,
items: <Widget>[
/* icons */
],
backgroundColor: Colors.transparent,
animationCurve: Curves.easeInOut,
animationDuration: Duration(milliseconds: 600),
onTap: (index) {
_controller.animateTo(index);
},
),
);
}
}
It should work with _controller.jumpTo(index) instead of _controller.animateTo(index), but you won't get animation effect
I really like that animation though.
I've done a lot of searching and it doesn't look like there's a any advice on this. However, I think the tabs source code successfully does something like this. I am very new to Flutter and Dart so maybe this will make more sense to you @rafalbednarczuk but in their tabs they add some listeners like
if (_controller != null) {
_controller.animation.addListener(_handleTabControllerAnimationTick);
_controller.addListener(_handleTabControllerTick);
_currentIndex = _controller.index;
}
And the listeners look like this:
void _handleTabControllerAnimationTick() {
assert(mounted);
if (!_controller.indexIsChanging && widget.isScrollable) {
// Sync the TabBar's scroll position with the TabBarView's PageView.
_currentIndex = _controller.index;
_scrollToControllerValue();
}
}
void _handleTabControllerTick() {
if (_controller.index != _currentIndex) {
_currentIndex = _controller.index;
if (widget.isScrollable)
_scrollToCurrentIndex();
}
setState(() {
// Rebuild the tabs after a (potentially animated) index change
// has completed.
});
}
Maybe this isn't the whole picture but what do you make of it? I'll do some testing later too and let you know how it goes.
[Edit] Oh, now I know why this would be difficult. You'd need to animate the bottom bar based off the controller's value as they do it in their code and not based off any one event given off by a listener (because you can't preemptively change the bottombar's index until you know for sure they've swiped to the other screen.)
void _scrollToControllerValue() {
final double leadingPosition = _currentIndex > 0 ? _tabCenteredScrollOffset(_currentIndex - 1) : null;
final double middlePosition = _tabCenteredScrollOffset(_currentIndex);
final double trailingPosition = _currentIndex < maxTabIndex ? _tabCenteredScrollOffset(_currentIndex + 1) : null;
final double index = _controller.index.toDouble();
final double value = _controller.animation.value;
double offset;
if (value == index - 1.0)
offset = leadingPosition ?? middlePosition;
else if (value == index + 1.0)
offset = trailingPosition ?? middlePosition;
else if (value == index)
offset = middlePosition;
else if (value < index)
offset = leadingPosition == null ? middlePosition : lerpDouble(middlePosition, leadingPosition, index - value);
else
offset = trailingPosition == null ? middlePosition : lerpDouble(middlePosition, trailingPosition, value - index);
_scrollController.jumpTo(offset);
}
Great job, looks great!
I just tried the CurvedNavigationBar. I stuck with one question/problem: I use Pageview to show the content. When you swipe to another page, I want to change the selected bottombar also, but there is only a initialIndex. How can I change the selected bottombaritem afterwards?