mirror of
https://github.com/flutter/samples.git
synced 2025-11-10 23:08:59 +00:00
Flutter 3.29 beta (#2571)
This commit is contained in:
@@ -69,10 +69,7 @@ class _PlatformAdaptingHomePageState extends State<PlatformAdaptingHomePage> {
|
||||
// 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(),
|
||||
);
|
||||
return SongsTab(key: songsTabKey, androidDrawer: _AndroidDrawer());
|
||||
}
|
||||
|
||||
// On iOS, the app uses a bottom tab paradigm. Here, each tab view sits inside
|
||||
@@ -91,10 +88,7 @@ class _PlatformAdaptingHomePageState extends State<PlatformAdaptingHomePage> {
|
||||
label: SongsTab.title,
|
||||
icon: SongsTab.iosIcon,
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
label: NewsTab.title,
|
||||
icon: NewsTab.iosIcon,
|
||||
),
|
||||
BottomNavigationBarItem(label: NewsTab.title, icon: NewsTab.iosIcon),
|
||||
BottomNavigationBarItem(
|
||||
label: ProfileTab.title,
|
||||
icon: ProfileTab.iosIcon,
|
||||
@@ -105,17 +99,17 @@ class _PlatformAdaptingHomePageState extends State<PlatformAdaptingHomePage> {
|
||||
assert(index <= 2 && index >= 0, 'Unexpected tab index: $index');
|
||||
return switch (index) {
|
||||
0 => CupertinoTabView(
|
||||
defaultTitle: SongsTab.title,
|
||||
builder: (context) => SongsTab(key: songsTabKey),
|
||||
),
|
||||
defaultTitle: SongsTab.title,
|
||||
builder: (context) => SongsTab(key: songsTabKey),
|
||||
),
|
||||
1 => CupertinoTabView(
|
||||
defaultTitle: NewsTab.title,
|
||||
builder: (context) => const NewsTab(),
|
||||
),
|
||||
defaultTitle: NewsTab.title,
|
||||
builder: (context) => const NewsTab(),
|
||||
),
|
||||
2 => CupertinoTabView(
|
||||
defaultTitle: ProfileTab.title,
|
||||
builder: (context) => const ProfileTab(),
|
||||
),
|
||||
defaultTitle: ProfileTab.title,
|
||||
builder: (context) => const ProfileTab(),
|
||||
),
|
||||
_ => const SizedBox.shrink(),
|
||||
};
|
||||
},
|
||||
@@ -161,8 +155,10 @@ class _AndroidDrawer extends StatelessWidget {
|
||||
title: const Text(NewsTab.title),
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
Navigator.push<void>(context,
|
||||
MaterialPageRoute(builder: (context) => const NewsTab()));
|
||||
Navigator.push<void>(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) => const NewsTab()),
|
||||
);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
@@ -170,8 +166,10 @@ class _AndroidDrawer extends StatelessWidget {
|
||||
title: const Text(ProfileTab.title),
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
Navigator.push<void>(context,
|
||||
MaterialPageRoute(builder: (context) => const ProfileTab()));
|
||||
Navigator.push<void>(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) => const ProfileTab()),
|
||||
);
|
||||
},
|
||||
),
|
||||
// Long drawer contents are often segmented.
|
||||
@@ -184,8 +182,10 @@ class _AndroidDrawer extends StatelessWidget {
|
||||
title: const Text(SettingsTab.title),
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
Navigator.push<void>(context,
|
||||
MaterialPageRoute(builder: (context) => const SettingsTab()));
|
||||
Navigator.push<void>(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) => const SettingsTab()),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
|
||||
@@ -32,8 +32,10 @@ class _NewsTabState extends State<NewsTab> {
|
||||
void initState() {
|
||||
colors = getRandomColors(_itemsLength);
|
||||
titles = List.generate(_itemsLength, (index) => generateRandomHeadline());
|
||||
contents =
|
||||
List.generate(_itemsLength, (index) => lorem(paragraphs: 1, words: 24));
|
||||
contents = List.generate(
|
||||
_itemsLength,
|
||||
(index) => lorem(paragraphs: 1, words: 24),
|
||||
);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@@ -44,9 +46,7 @@ class _NewsTabState extends State<NewsTab> {
|
||||
child: Card(
|
||||
elevation: 1.5,
|
||||
margin: const EdgeInsets.fromLTRB(6, 12, 6, 0),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)),
|
||||
child: InkWell(
|
||||
// Make it splash on Android. It would happen automatically if this
|
||||
// was a real card but this is just a demo. Skip the splash on iOS.
|
||||
@@ -76,9 +76,7 @@ class _NewsTabState extends State<NewsTab> {
|
||||
),
|
||||
),
|
||||
const Padding(padding: EdgeInsets.only(top: 8)),
|
||||
Text(
|
||||
contents[index],
|
||||
),
|
||||
Text(contents[index]),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -96,9 +94,7 @@ class _NewsTabState extends State<NewsTab> {
|
||||
|
||||
Widget _buildAndroid(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text(NewsTab.title),
|
||||
),
|
||||
appBar: AppBar(title: const Text(NewsTab.title)),
|
||||
body: ListView.builder(
|
||||
itemCount: _itemsLength,
|
||||
itemBuilder: _listBuilder,
|
||||
@@ -118,9 +114,6 @@ class _NewsTabState extends State<NewsTab> {
|
||||
|
||||
@override
|
||||
Widget build(context) {
|
||||
return PlatformWidget(
|
||||
androidBuilder: _buildAndroid,
|
||||
iosBuilder: _buildIos,
|
||||
);
|
||||
return PlatformWidget(androidBuilder: _buildAndroid, iosBuilder: _buildIos);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,9 +54,7 @@ class ProfileTab extends StatelessWidget {
|
||||
'Into the darkness',
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: Container(),
|
||||
),
|
||||
Expanded(child: Container()),
|
||||
const LogOutButton(),
|
||||
],
|
||||
),
|
||||
@@ -71,9 +69,7 @@ class ProfileTab extends StatelessWidget {
|
||||
|
||||
Widget _buildAndroid(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text(title),
|
||||
),
|
||||
appBar: AppBar(title: const Text(title)),
|
||||
body: _buildBody(context),
|
||||
);
|
||||
}
|
||||
@@ -103,10 +99,7 @@ class ProfileTab extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(context) {
|
||||
return PlatformWidget(
|
||||
androidBuilder: _buildAndroid,
|
||||
iosBuilder: _buildIos,
|
||||
);
|
||||
return PlatformWidget(androidBuilder: _buildAndroid, iosBuilder: _buildIos);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,10 +128,7 @@ class PreferenceCard extends StatelessWidget {
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 40),
|
||||
child: Center(
|
||||
child: Text(
|
||||
content,
|
||||
style: const TextStyle(fontSize: 48),
|
||||
),
|
||||
child: Text(content, style: const TextStyle(fontSize: 48)),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -172,7 +162,8 @@ class PreferenceCard extends StatelessWidget {
|
||||
|
||||
class LogOutButton extends StatelessWidget {
|
||||
static const _logoutMessage = Text(
|
||||
"You can't actually log out! This is just a demo of how alerts work.");
|
||||
"You can't actually log out! This is just a demo of how alerts work.",
|
||||
);
|
||||
|
||||
const LogOutButton({super.key});
|
||||
|
||||
@@ -252,9 +243,6 @@ class LogOutButton extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(context) {
|
||||
return PlatformWidget(
|
||||
androidBuilder: _buildAndroid,
|
||||
iosBuilder: _buildIos,
|
||||
);
|
||||
return PlatformWidget(androidBuilder: _buildAndroid, iosBuilder: _buildIos);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,9 +91,7 @@ class _SettingsTabState extends State<SettingsTab> {
|
||||
|
||||
Widget _buildAndroid(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text(SettingsTab.title),
|
||||
),
|
||||
appBar: AppBar(title: const Text(SettingsTab.title)),
|
||||
body: _buildList(),
|
||||
);
|
||||
}
|
||||
@@ -107,9 +105,6 @@ class _SettingsTabState extends State<SettingsTab> {
|
||||
|
||||
@override
|
||||
Widget build(context) {
|
||||
return PlatformWidget(
|
||||
androidBuilder: _buildAndroid,
|
||||
iosBuilder: _buildIos,
|
||||
);
|
||||
return PlatformWidget(androidBuilder: _buildAndroid, iosBuilder: _buildIos);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,8 +42,13 @@ class SongDetailTab extends StatelessWidget {
|
||||
// to build while the hero transition is mid-flight.
|
||||
//
|
||||
// It could either be specified here or in SongsTab.
|
||||
flightShuttleBuilder: (context, animation, flightDirection,
|
||||
fromHeroContext, toHeroContext) {
|
||||
flightShuttleBuilder: (
|
||||
context,
|
||||
animation,
|
||||
flightDirection,
|
||||
fromHeroContext,
|
||||
toHeroContext,
|
||||
) {
|
||||
return HeroAnimatingSongCard(
|
||||
song: song,
|
||||
color: color,
|
||||
@@ -51,26 +56,24 @@ class SongDetailTab extends StatelessWidget {
|
||||
);
|
||||
},
|
||||
),
|
||||
const Divider(
|
||||
height: 0,
|
||||
color: Colors.grey,
|
||||
),
|
||||
const Divider(height: 0, color: Colors.grey),
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: 10,
|
||||
itemBuilder: (context, index) => switch (index) {
|
||||
0 => const Padding(
|
||||
padding: EdgeInsets.only(left: 15, top: 16, bottom: 8),
|
||||
child: Text(
|
||||
'You might also like:',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
itemBuilder:
|
||||
(context, index) => switch (index) {
|
||||
0 => const Padding(
|
||||
padding: EdgeInsets.only(left: 15, top: 16, bottom: 8),
|
||||
child: Text(
|
||||
'You might also like:',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
_ => const SongPlaceholderTile(),
|
||||
},
|
||||
_ => const SongPlaceholderTile(),
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -83,10 +86,7 @@ class SongDetailTab extends StatelessWidget {
|
||||
// ===========================================================================
|
||||
|
||||
Widget _buildAndroid(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text(song)),
|
||||
body: _buildBody(),
|
||||
);
|
||||
return Scaffold(appBar: AppBar(title: Text(song)), body: _buildBody());
|
||||
}
|
||||
|
||||
Widget _buildIos(BuildContext context) {
|
||||
@@ -101,9 +101,6 @@ class SongDetailTab extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(context) {
|
||||
return PlatformWidget(
|
||||
androidBuilder: _buildAndroid,
|
||||
iosBuilder: _buildIos,
|
||||
);
|
||||
return PlatformWidget(androidBuilder: _buildAndroid, iosBuilder: _buildIos);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,9 +55,10 @@ class _SongsTabState extends State<SongsTab> {
|
||||
|
||||
// Show a slightly different color palette. Show poppy-ier colors on iOS
|
||||
// due to lighter contrasting bars and tone it down on Android.
|
||||
final color = defaultTargetPlatform == TargetPlatform.iOS
|
||||
? colors[index]
|
||||
: colors[index].shade400;
|
||||
final color =
|
||||
defaultTargetPlatform == TargetPlatform.iOS
|
||||
? colors[index]
|
||||
: colors[index].shade400;
|
||||
|
||||
return SafeArea(
|
||||
top: false,
|
||||
@@ -68,15 +69,17 @@ class _SongsTabState extends State<SongsTab> {
|
||||
song: songNames[index],
|
||||
color: color,
|
||||
heroAnimation: const AlwaysStoppedAnimation(0),
|
||||
onPressed: () => Navigator.of(context).push<void>(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => SongDetailTab(
|
||||
id: index,
|
||||
song: songNames[index],
|
||||
color: color,
|
||||
onPressed:
|
||||
() => Navigator.of(context).push<void>(
|
||||
MaterialPageRoute(
|
||||
builder:
|
||||
(context) => SongDetailTab(
|
||||
id: index,
|
||||
song: songNames[index],
|
||||
color: color,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -114,8 +117,8 @@ class _SongsTabState extends State<SongsTab> {
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.refresh),
|
||||
onPressed: () async =>
|
||||
await _androidRefreshKey.currentState!.show(),
|
||||
onPressed:
|
||||
() async => await _androidRefreshKey.currentState!.show(),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.shuffle),
|
||||
@@ -146,9 +149,7 @@ class _SongsTabState extends State<SongsTab> {
|
||||
child: const Icon(CupertinoIcons.shuffle),
|
||||
),
|
||||
),
|
||||
CupertinoSliverRefreshControl(
|
||||
onRefresh: _refreshData,
|
||||
),
|
||||
CupertinoSliverRefreshControl(onRefresh: _refreshData),
|
||||
SliverSafeArea(
|
||||
top: false,
|
||||
sliver: SliverPadding(
|
||||
@@ -167,9 +168,6 @@ class _SongsTabState extends State<SongsTab> {
|
||||
|
||||
@override
|
||||
Widget build(context) {
|
||||
return PlatformWidget(
|
||||
androidBuilder: _buildAndroid,
|
||||
iosBuilder: _buildIos,
|
||||
);
|
||||
return PlatformWidget(androidBuilder: _buildAndroid, iosBuilder: _buildIos);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,13 +20,14 @@ class PlatformWidget extends StatelessWidget {
|
||||
@override
|
||||
Widget build(context) {
|
||||
assert(
|
||||
defaultTargetPlatform == TargetPlatform.android ||
|
||||
defaultTargetPlatform == TargetPlatform.iOS,
|
||||
'Unexpected platform $defaultTargetPlatform');
|
||||
defaultTargetPlatform == TargetPlatform.android ||
|
||||
defaultTargetPlatform == TargetPlatform.iOS,
|
||||
'Unexpected platform $defaultTargetPlatform',
|
||||
);
|
||||
return switch (defaultTargetPlatform) {
|
||||
TargetPlatform.android => androidBuilder(context),
|
||||
TargetPlatform.iOS => iosBuilder(context),
|
||||
_ => const SizedBox.shrink()
|
||||
_ => const SizedBox.shrink(),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -65,8 +66,9 @@ class _PressableCardState extends State<PressableCard>
|
||||
vsync: this,
|
||||
duration: const Duration(milliseconds: 40),
|
||||
);
|
||||
elevationAnimation =
|
||||
controller.drive(CurveTween(curve: Curves.easeInOutCubic));
|
||||
elevationAnimation = controller.drive(
|
||||
CurveTween(curve: Curves.easeInOutCubic),
|
||||
);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@@ -99,8 +101,10 @@ class _PressableCardState extends State<PressableCard>
|
||||
// hero animation. You likely want to modularize them more in your own
|
||||
// app.
|
||||
child: AnimatedBuilder(
|
||||
animation:
|
||||
Listenable.merge([elevationAnimation, widget.flattenAnimation]),
|
||||
animation: Listenable.merge([
|
||||
elevationAnimation,
|
||||
widget.flattenAnimation,
|
||||
]),
|
||||
child: widget.child,
|
||||
builder: (context, child) {
|
||||
return Transform.scale(
|
||||
@@ -110,7 +114,7 @@ class _PressableCardState extends State<PressableCard>
|
||||
child: Padding(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(vertical: 16, horizontal: 16) *
|
||||
flatten,
|
||||
flatten,
|
||||
child: PhysicalModel(
|
||||
elevation:
|
||||
((1 - elevationAnimation.value) * 10 + 10) * flatten,
|
||||
@@ -192,7 +196,8 @@ class HeroAnimatingSongCard extends StatelessWidget {
|
||||
),
|
||||
// The play button grows in the hero animation.
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 45) *
|
||||
padding:
|
||||
const EdgeInsets.only(bottom: 45) *
|
||||
(1 - heroAnimation.value),
|
||||
child: Container(
|
||||
height: playButtonSize,
|
||||
@@ -202,8 +207,11 @@ class HeroAnimatingSongCard extends StatelessWidget {
|
||||
color: Colors.black12,
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child: Icon(Icons.play_arrow,
|
||||
size: playButtonSize, color: Colors.black38),
|
||||
child: Icon(
|
||||
Icons.play_arrow,
|
||||
size: playButtonSize,
|
||||
color: Colors.black38,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -234,9 +242,7 @@ class SongPlaceholderTile extends StatelessWidget {
|
||||
color: Theme.of(context).textTheme.bodyMedium!.color,
|
||||
width: 130,
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(left: 12),
|
||||
),
|
||||
const Padding(padding: EdgeInsets.only(left: 12)),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -342,9 +348,7 @@ void showChoices(BuildContext context, List<String> choices) {
|
||||
return Center(
|
||||
child: Text(
|
||||
choices[index],
|
||||
style: const TextStyle(
|
||||
fontSize: 21,
|
||||
),
|
||||
style: const TextStyle(fontSize: 21),
|
||||
),
|
||||
);
|
||||
}),
|
||||
|
||||
@@ -3,7 +3,7 @@ description: A project showcasing a Flutter app following different platform IA
|
||||
version: 1.0.0+1
|
||||
|
||||
environment:
|
||||
sdk: ^3.5.0
|
||||
sdk: ^3.7.0-0
|
||||
|
||||
dependencies:
|
||||
english_words: ^4.0.0
|
||||
|
||||
Reference in New Issue
Block a user