Created
November 17, 2023 20:25
-
-
Save leighajarett/f213d24e8e29d0f10f517a6df84cee26 to your computer and use it in GitHub Desktop.
Slider with TabBar
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
void main() => runApp(MyApp()); | |
// More netural / iOS friendly theme | |
final ColorScheme iosColorScheme = ColorScheme( | |
brightness: Brightness.light, | |
primary: Color(0xFF007AFF), // iOS blue | |
onPrimary: Colors.white, // Text color on primary color (typically white) | |
secondary: Color(0xFFF8F8F8), // Lighter blue for secondary elements | |
onSecondary: Colors.black, // Text color on secondary color (typically white) | |
error: Colors.red, // Default Material Design error color | |
onError: Colors.white, // Text color on error color | |
background: Color(0xFFF8F8F8), // Light background color (off white) | |
onBackground: Colors.black, // Text color on background color | |
surface: Colors.white, // Card and dialog background color | |
onSurface: Colors.black, // Text color on surface color | |
); | |
final ThemeData iosTheme = ThemeData.from(colorScheme: iosColorScheme); | |
class MyApp extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
theme: iosTheme, | |
home: Root(), | |
); | |
} | |
} | |
// Create a concise way to store information for the tabs | |
class TabItem { | |
final int index; | |
final IconData icon; | |
final Widget page; | |
TabItem({required this.index, required this.icon, required this.page}); | |
} | |
// Example with two tabs | |
final List<TabItem> tabItems = [ | |
TabItem(index: 0, icon: Icons.home, page: Home(destinationIndex: 0)), | |
TabItem(index: 1, icon: Icons.business, page: Center(child: Text('Business Page'))), | |
// Add more TabItem entries for additional tabs | |
]; | |
class Root extends StatefulWidget { | |
@override | |
State<Root> createState() => _RootState(); | |
} | |
class _RootState extends State<Root> with TickerProviderStateMixin { | |
late TabController _tabController; | |
late List<GlobalKey<NavigatorState>> _navigatorKeys; | |
int selectedIndex = 0; // Add a selectedIndex state | |
@override | |
void initState() { | |
super.initState(); | |
_navigatorKeys = List.generate(tabItems.length, (index) => GlobalKey<NavigatorState>()); | |
_tabController = TabController(length: tabItems.length, vsync: this); | |
_tabController.addListener(_handleTabSelection); | |
} | |
@override | |
void dispose() { | |
_tabController.removeListener(_handleTabSelection); | |
_tabController.dispose(); | |
super.dispose(); | |
} | |
void _handleTabSelection() { | |
if (mounted) { | |
setState(() { | |
selectedIndex = _tabController.index; // Update selectedIndex on tab change | |
}); | |
} | |
} | |
double get circlePosition { | |
double screenWidth = MediaQuery.of(context).size.width; | |
double tabWidth = screenWidth / tabItems.length; | |
return tabWidth * selectedIndex + (tabWidth - 20) / 2; // Position the circle in the center of the tab | |
} | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
body: TabBarView( | |
controller: _tabController, | |
children: tabItems.map((tabItem) { | |
return Navigator( | |
key: _navigatorKeys[tabItem.index], | |
onGenerateRoute: (settings) => MaterialPageRoute( | |
builder: (context) => tabItem.page, | |
), | |
); | |
}).toList(), | |
), | |
bottomNavigationBar: Stack( | |
alignment: Alignment.bottomCenter, | |
children: [ | |
TabBar( | |
indicatorColor: Colors.transparent, | |
overlayColor: MaterialStateProperty.all(Colors.transparent), | |
controller: _tabController, | |
tabs: tabItems.map((tabItem) => Tab(icon: Icon(tabItem.icon, color: Colors.black))).toList(), | |
), | |
AnimatedPositioned( | |
duration: const Duration(milliseconds: 300), | |
curve: Curves.easeOut, | |
left: circlePosition, | |
bottom: 0, | |
child: Container( | |
width: 20, | |
height: 20, | |
decoration: BoxDecoration( | |
color: Color(0xFF007AFF), | |
shape: BoxShape.circle, | |
), | |
), | |
), | |
], | |
), | |
); | |
} | |
} | |
class Home extends StatelessWidget { | |
final int destinationIndex; | |
const Home({Key? key, required this.destinationIndex}) : super(key: key); | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar(title: Text('Home Page')), | |
body: Center( | |
child: ElevatedButton( | |
child: Text('Go to List Page'), | |
onPressed: () { | |
Navigator.of(context).push(MaterialPageRoute( | |
builder: (context) => ListPage(), | |
)); | |
}, | |
), | |
), | |
); | |
} | |
} | |
class ListPage extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar(title: Text('List Page')), | |
body: Center( | |
child: Text('Welcome to List Page'), | |
), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment