import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'songs_tab.dart'; import 'news_tab.dart'; import 'profile_tab.dart'; import 'settings_tab.dart'; import 'widgets.dart'; void main() => runApp(MyAdaptingApp()); class MyAdaptingApp extends StatelessWidget { @override Widget build(context) { // Change this value to better see animations. timeDilation = 1; // Either Material or Cupertino widgets work in either Material or Cupertino // Apps. return MaterialApp( title: 'Adaptive Music App', theme: ThemeData( // Use the green theme for Material widgets. primarySwatch: Colors.green, ), builder: (context, child) { return CupertinoTheme( // Instead of letting Cupertino widgets auto-adapt to the Material // theme (which is green), this app will use a different theme // for Cupertino (which is blue by default). data: CupertinoThemeData(), child: Material(child: child), ); }, home: PlatformAdaptingHomePage(), ); } } // Shows a different type of scaffold depending on the platform. // // This file has the most amount of non-sharable code since it behaves the most // differently between the platforms. // // These differences are also subjective and have more than one 'right' answer // depending on the app and content. class PlatformAdaptingHomePage extends StatefulWidget { @override _PlatformAdaptingHomePageState createState() => _PlatformAdaptingHomePageState(); } class _PlatformAdaptingHomePageState extends State { // This app keeps a global key for the songs tab because it owns a bunch of // data. Since changing platform reparents those tabs into different // scaffolds, keeping a global key to it lets this app keep that tab's data as // the platform toggles. // // This isn't needed for apps that doesn't toggle platforms while running. final songsTabKey = GlobalKey(); // In Material, this app uses the hamburger menu paradigm and flatly lists // all 4 possible tabs. This drawer is injected into the songs tab which is // actually building the scaffold around the drawer. Widget _buildAndroidHomePage(BuildContext context) { return SongsTab( key: songsTabKey, androidDrawer: _AndroidDrawer(), ); } // On iOS, the app uses a bottom tab paradigm. Here, each tab view sits inside // a tab in the tab scaffold. The tab scaffold also positions the tab bar // in a row at the bottom. // // An important thing to note is that while a Material Drawer can display a // large number of items, a tab bar cannot. To illustrate one way of adjusting // for this, the app folds its fourth tab (the settings page) into the // third tab. This is a common pattern on iOS. Widget _buildIosHomePage(BuildContext context) { return CupertinoTabScaffold( tabBar: CupertinoTabBar( items: [ BottomNavigationBarItem( title: Text(SongsTab.title), icon: SongsTab.iosIcon), BottomNavigationBarItem( title: Text(NewsTab.title), icon: NewsTab.iosIcon), BottomNavigationBarItem( title: Text(ProfileTab.title), icon: ProfileTab.iosIcon), ], ), tabBuilder: (context, index) { switch (index) { case 0: return CupertinoTabView( defaultTitle: SongsTab.title, builder: (context) => SongsTab(key: songsTabKey), ); case 1: return CupertinoTabView( defaultTitle: NewsTab.title, builder: (context) => NewsTab(), ); case 2: return CupertinoTabView( defaultTitle: ProfileTab.title, builder: (context) => ProfileTab(), ); default: assert(false, 'Unexpected tab'); return null; } }, ); } @override Widget build(context) { return PlatformWidget( androidBuilder: _buildAndroidHomePage, iosBuilder: _buildIosHomePage, ); } } class _AndroidDrawer extends StatelessWidget { @override Widget build(BuildContext context) { return Drawer( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ DrawerHeader( decoration: BoxDecoration(color: Colors.green), child: Padding( padding: const EdgeInsets.only(bottom: 20), child: Icon( Icons.account_circle, color: Colors.green.shade800, size: 96, ), ), ), ListTile( leading: SongsTab.androidIcon, title: Text(SongsTab.title), onTap: () { Navigator.pop(context); }, ), ListTile( leading: NewsTab.androidIcon, title: Text(NewsTab.title), onTap: () { Navigator.pop(context); Navigator.push( context, MaterialPageRoute(builder: (context) => NewsTab())); }, ), ListTile( leading: ProfileTab.androidIcon, title: Text(ProfileTab.title), onTap: () { Navigator.pop(context); Navigator.push(context, MaterialPageRoute(builder: (context) => ProfileTab())); }, ), // Long drawer contents are often segmented. Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Divider(), ), ListTile( leading: SettingsTab.androidIcon, title: Text(SettingsTab.title), onTap: () { Navigator.pop(context); Navigator.push(context, MaterialPageRoute(builder: (context) => SettingsTab())); }, ), ], ), ); } }