custom_tabbarview
This package is almost identical to the TabBarView API in the Flutter SDK, but with enhanced customization capabilities.
Presets
|
|
|
|
| fade | stack | carousel |
|
|
|
|
| toss1 | toss2 |
Feature
- It's a direct clone of TabBarView from the Flutter SDK, so more than 95% of the codebase is identical and reliable.
- The widgets in children(tabs) are all built lazily, with keepAlive behavior as needed.
- Transition animations are 100% customizable based on transition rate.
- There are plenty of presets to get you started quickly, and hints for customization.
Migration guide
from TabBarView
If you were previously using TabBarView, you can follow these steps to migrate.
- Change from
TabBarViewtoCustomTabBarView
If you want to use the main feature -- .builder in addition, you can follow the steps below.
- Rename
chindrentotabs. - Implement
buildertype ofCustomTabBarViewBuilderor just use other named constructor.
CustomTabBarViewBuilder
The type of builder method used globally in CustomTabBarView.
It returns a Widget and takes the following arguments:
context:BuildContextfor the widget.pageController: APageControllerfor PageView that internally implements TabBarView.childrenWithKey: The children or tabs passed in.
However, the implementation of TabBarView temporarily changes the order of the child widgets on transition.index: The index of the widget currently being displayed in the TabBarView.
Important
You can get the child that match the TabController with childrenWithKey[index].
Example
class HomeTab extends StatefulWidget {
const HomeTab({super.key});
@override
State<HomeTab> createState() => _HomeTabState();
}
class _HomeTabState extends State<HomeTab> with SingleTickerProviderStateMixin {
late TabController _tabController;
final List<Widget> _children = [
const HomePage(),
const Page1(),
const Page2(),
const Page3(),
const Page4(),
];
@override
void initState() {
super.initState();
_tabController = TabController(
length: 5,
initialIndex: 0,
vsync: this,
);
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final width = MediaQuery.sizeOf(context).width;
return Scaffold(
appBar: AppBar(
title: const Text('CustomTabBarView Demo'),
),
backgroundColor: Colors.white,
body: CustomTabBarView.builder(
controller: _tabController,
physics: const PageScrollPhysics(),
dragStartBehavior: DragStartBehavior.down,
tabs: _children,
builder: (context, pageController, childrenWithKey, index) {
return AnimatedBuilder(
animation: pageController,
builder: (context, child) {
final page =
pageController.page ?? pageController.initialPage.toDouble();
final offset = (page - index) * pageController.viewportFraction;
final dx = offset * width * 0.8;
final scale = 1 - offset.abs() * 0.1;
final opacity = 1 - offset.abs() * 2;
return Opacity(
opacity: opacity.clamp(0.0, 1.0),
child: Transform.scale(
scale: scale,
child:
Transform.translate(offset: Offset(dx, 0), child: child),
),
);
},
child: childrenWithKey[index],
);
},
),
bottomNavigationBar: SafeArea(
child: Transform.flip(
flipY: true,
child: SizedBox(
height: 60,
child: TabBar(
controller: _tabController,
isScrollable: false,
labelColor: Theme.of(context).primaryColorDark,
indicatorColor: Theme.of(context).primaryColorDark,
labelStyle: const TextStyle(fontSize: 10),
tabs: [
Transform.flip(
flipY: true,
child: const Tab(icon: Icon(Icons.home), text: '홈'),
),
Transform.flip(
flipY: true,
child: const Tab(icon: Icon(Icons.one_k), text: 'Page 1'),
),
Transform.flip(
flipY: true,
child: const Tab(icon: Icon(Icons.two_k), text: 'Page 2'),
),
Transform.flip(
flipY: true,
child: const Tab(icon: Icon(Icons.three_k), text: 'Page 3'),
),
Transform.flip(
flipY: true,
child: const Tab(icon: Icon(Icons.four_k), text: 'Page 4'),
),
],
),
),
),
),
);
}
}