mirror of
https://github.com/flutter/samples.git
synced 2025-11-08 22:09:06 +00:00
Add a Material/Cupertino adaptive application example (#69)
This commit is contained in:
186
platform_design/lib/main.dart
Normal file
186
platform_design/lib/main.dart
Normal file
@@ -0,0 +1,186 @@
|
||||
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<PlatformAdaptingHomePage> {
|
||||
// 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(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(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()
|
||||
));
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user