mirror of https://github.com/flutter/samples.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
169 lines
4.6 KiB
169 lines
4.6 KiB
5 years ago
|
import 'package:flutter/cupertino.dart';
|
||
|
import 'package:flutter/foundation.dart';
|
||
|
import 'package:flutter/material.dart';
|
||
|
|
||
|
import 'song_detail_tab.dart';
|
||
|
import 'utils.dart';
|
||
|
import 'widgets.dart';
|
||
|
|
||
|
class SongsTab extends StatefulWidget {
|
||
|
static const title = 'Songs';
|
||
|
static const androidIcon = Icon(Icons.music_note);
|
||
|
static const iosIcon = Icon(CupertinoIcons.music_note);
|
||
|
|
||
|
const SongsTab({ Key key, this.androidDrawer }) : super(key: key);
|
||
|
|
||
|
final Widget androidDrawer;
|
||
|
|
||
|
@override
|
||
|
_SongsTabState createState() => _SongsTabState();
|
||
|
}
|
||
|
|
||
|
class _SongsTabState extends State<SongsTab> {
|
||
|
static const _itemsLength = 50;
|
||
|
|
||
|
final _androidRefreshKey = GlobalKey<RefreshIndicatorState>();
|
||
|
|
||
|
List<MaterialColor> colors;
|
||
|
List<String> songNames;
|
||
|
|
||
|
@override
|
||
|
void initState() {
|
||
|
_setData();
|
||
|
super.initState();
|
||
|
}
|
||
|
|
||
|
void _setData() {
|
||
|
colors = getRandomColors(_itemsLength);
|
||
|
songNames = getRandomNames(_itemsLength);
|
||
|
}
|
||
|
|
||
|
Future<void> _refreshData() {
|
||
|
return Future.delayed(
|
||
|
// This is just an arbitrary delay that simulates some network activity.
|
||
|
const Duration(seconds: 2),
|
||
|
() => setState(() => _setData()),
|
||
|
);
|
||
|
}
|
||
|
|
||
|
Widget _listBuilder(context, index) {
|
||
|
if (index >= _itemsLength)
|
||
|
return null;
|
||
|
|
||
|
// 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;
|
||
|
|
||
|
return SafeArea(
|
||
|
top: false,
|
||
|
bottom: false,
|
||
|
child: Hero(
|
||
|
tag: index,
|
||
|
child: HeroAnimatingSongCard(
|
||
|
song: songNames[index],
|
||
|
color: color,
|
||
|
heroAnimation: AlwaysStoppedAnimation(0),
|
||
|
onPressed: () => Navigator.of(context).push(MaterialPageRoute(
|
||
|
builder: (context) => SongDetailTab(
|
||
|
id: index,
|
||
|
song: songNames[index],
|
||
|
color: color,
|
||
|
),
|
||
|
)),
|
||
|
),
|
||
|
),
|
||
|
);
|
||
|
}
|
||
|
|
||
|
void _togglePlatform() {
|
||
|
TargetPlatform _getOppositePlatform() {
|
||
|
if (defaultTargetPlatform == TargetPlatform.iOS) {
|
||
|
return TargetPlatform.android;
|
||
|
} else {
|
||
|
return TargetPlatform.iOS;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
debugDefaultTargetPlatformOverride = _getOppositePlatform();
|
||
|
// This rebuilds the application. This should obviously never be
|
||
|
// done in a real app but it's done here since this app
|
||
|
// unrealistically toggles the current platform for demonstration
|
||
|
// purposes.
|
||
|
WidgetsBinding.instance.reassembleApplication();
|
||
|
}
|
||
|
|
||
|
// ===========================================================================
|
||
|
// Non-shared code below because:
|
||
|
// - Android and iOS have different scaffolds
|
||
|
// - There are differenc items in the app bar / nav bar
|
||
|
// - Android has a hamburger drawer, iOS has bottom tabs
|
||
|
// - The iOS nav bar is scrollable, Android is not
|
||
|
// - Pull-to-refresh works differently, and Android has a button to trigger it too
|
||
|
//
|
||
|
// And these are all design time choices that doesn't have a single 'right'
|
||
|
// answer.
|
||
|
// ===========================================================================
|
||
|
Widget _buildAndroid(context) {
|
||
|
return Scaffold(
|
||
|
appBar: AppBar(
|
||
|
title: Text(SongsTab.title),
|
||
|
actions: [
|
||
|
IconButton(
|
||
|
icon: Icon(Icons.refresh),
|
||
|
onPressed: () async => await _androidRefreshKey.currentState.show(),
|
||
|
),
|
||
|
IconButton(
|
||
|
icon: Icon(Icons.shuffle),
|
||
|
onPressed: _togglePlatform,
|
||
|
),
|
||
|
],
|
||
|
),
|
||
|
drawer: widget.androidDrawer,
|
||
|
body: RefreshIndicator(
|
||
|
key: _androidRefreshKey,
|
||
|
onRefresh: _refreshData,
|
||
|
child: ListView.builder(
|
||
|
padding: EdgeInsets.symmetric(vertical: 12),
|
||
|
itemBuilder: _listBuilder,
|
||
|
),
|
||
|
),
|
||
|
);
|
||
|
}
|
||
|
|
||
|
Widget _buildIos(context) {
|
||
|
return CustomScrollView(
|
||
|
slivers: [
|
||
|
CupertinoSliverNavigationBar(
|
||
|
trailing: CupertinoButton(
|
||
|
padding: EdgeInsets.zero,
|
||
|
child: Icon(CupertinoIcons.shuffle),
|
||
|
onPressed: _togglePlatform,
|
||
|
),
|
||
|
),
|
||
|
CupertinoSliverRefreshControl(
|
||
|
onRefresh: _refreshData,
|
||
|
),
|
||
|
SliverSafeArea(
|
||
|
top: false,
|
||
|
sliver: SliverPadding(
|
||
|
padding: EdgeInsets.symmetric(vertical: 12),
|
||
|
sliver: SliverList(
|
||
|
delegate: SliverChildBuilderDelegate(_listBuilder),
|
||
|
),
|
||
|
),
|
||
|
),
|
||
|
],
|
||
|
);
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
Widget build(context) {
|
||
|
return PlatformWidget(
|
||
|
androidBuilder: _buildAndroid,
|
||
|
iosBuilder: _buildIos,
|
||
|
);
|
||
|
}
|
||
|
}
|