curved_dual_tab_bar 0.2.4
curved_dual_tab_bar: ^0.2.4 copied to clipboard
Curved dual-segment tab bar with an animated S-curve divider, built on a real Material TabBar — drop-in DEPOSIT/WITHDRAW style headers with full color/gradient/border theming.
curved_dual_tab_bar #
A curved, two-segment tab bar with an animated S-curve divider — built on a real Material TabBar, not a fake gesture layer.
▶ Live Demo — every styling knob demoed interactively.
- 🎯 A real
TabBarunderneath — tap targets, the selection indicator, ripple/hover/focus feedback and a11y semantics all come from Flutter's ownTabBar; this widget only paints the curved background around it. - 🎨 Fully themeable — solid colors, gradients, per-side borders, divider color/width, corner radius, lean amplitude, animation duration/curve.
- 🧩 Two ways to use it —
CurvedDualTabBar(drop-in header, owns its ownTabController) orCurvedTabBackground(the standalone curve painter, if you already drive a nativeTabBaryourself).
Screenshot #
| Demo app |
|---|
![]() |
| Captured on a physical Android device from the example app |
Try every variant live at the demo site.
Install #
dependencies:
curved_dual_tab_bar: ^0.2.0
Usage #
import 'package:curved_dual_tab_bar/curved_dual_tab_bar.dart';
CurvedDualTabBar(
titles: const ['DEPOSIT', 'WITHDRAW'],
selectedIndex: selectedIndex,
onChanged: (i) => setState(() => selectedIndex = i),
)
That's a fully working, animated, two-tab header — CurvedDualTabBar creates and owns its own TabController internally, kept in sync with selectedIndex/onChanged.
Already have a native TabBar? #
Use CurvedTabBackground as pure decoration and let your own TabController drive it:
CurvedTabBackground(
selectedIndex: selectedIndex,
progress: tabController.animation,
child: TabBar(
controller: tabController,
indicatorColor: Colors.transparent,
dividerColor: Colors.transparent,
tabs: const [Tab(text: 'LEFT'), Tab(text: 'RIGHT')],
),
)
Styling #
Both widgets accept activeColor/inactiveColor (or activeGradient/inactiveGradient), unselectedColor/unselectedBorderColor, activeBorderColor/inactiveBorderColor, borderRadius, leanAmplitude (how much the S-curve leans), and duration/curve for the transition animation. See the example app for every combination demoed side by side.
Divider styling #
The seam itself has its own set of knobs, independent of the fill colors:
CurvedDualTabBar(
titles: const ['DEPOSIT', 'WITHDRAW'],
selectedIndex: selectedIndex,
onChanged: (i) => setState(() => selectedIndex = i),
dividerGradient: const LinearGradient(colors: [Colors.pink, Colors.purple, Colors.blue]),
dividerWidth: 3,
dividerCap: StrokeCap.round,
dividerShadow: const BoxShadow(color: Colors.black26, blurRadius: 10, spreadRadius: 1),
topControlOffset: const Offset(16, 6),
bottomControlOffset: const Offset(-16, -6),
)
dividerColor/dividerWidth— solid stroke color and width.dividerGradient— overridesdividerColorwith a gradient stroke.dividerCap—StrokeCap.butt(default, flat cut at the top/bottom edges) or.round/.square.dividerShadow— aBoxShadowstroked once behind the seam as a soft glow/shadow; itsspreadRadiuswidens the stroke rather than growing a filled shape.topControlOffset/bottomControlOffset— nudge the curve's own bezier control points directly. The curve's default shape keeps a flat tangent at the top/bottom edges (so it grazes them like a wave crest/trough); these offsets break that and let you reshape the S-curve independent ofleanAmplitude.
Why exactly 2 tabs? #
The curve divider is a single S-shaped seam between an active and an inactive half — that only has a well-defined shape for 2 segments. CurvedDualTabBar asserts titles.length == 2 for that reason. For more segments, use a plain TabBar.
License #
MIT — see LICENSE.
