flutter/examples/flutter_gallery/lib/gallery/home.dart
Chris Bracken 20fb6621eb
Apply media padding in ListTile (#13545)
Applies media padding (e.g. iOS safe area insets) around the list tile
children inside the InkWell.

Also adds safe area around gallery section titles for consistency with
surrounding list tiles.
2017-12-13 18:39:36 -08:00

225 lines
7.2 KiB
Dart

// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'drawer.dart';
import 'item.dart';
const double _kFlexibleSpaceMaxHeight = 256.0;
const String _kGalleryAssetsPackage = 'flutter_gallery_assets';
class _BackgroundLayer {
_BackgroundLayer({ int level, double parallax })
: assetName = 'appbar/appbar_background_layer$level.png',
assetPackage = _kGalleryAssetsPackage,
parallaxTween = new Tween<double>(begin: 0.0, end: parallax);
final String assetName;
final String assetPackage;
final Tween<double> parallaxTween;
}
final List<_BackgroundLayer> _kBackgroundLayers = <_BackgroundLayer>[
new _BackgroundLayer(level: 0, parallax: _kFlexibleSpaceMaxHeight),
new _BackgroundLayer(level: 1, parallax: _kFlexibleSpaceMaxHeight),
new _BackgroundLayer(level: 2, parallax: _kFlexibleSpaceMaxHeight / 2.0),
new _BackgroundLayer(level: 3, parallax: _kFlexibleSpaceMaxHeight / 4.0),
new _BackgroundLayer(level: 4, parallax: _kFlexibleSpaceMaxHeight / 2.0),
new _BackgroundLayer(level: 5, parallax: _kFlexibleSpaceMaxHeight)
];
class _AppBarBackground extends StatelessWidget {
const _AppBarBackground({ Key key, this.animation }) : super(key: key);
final Animation<double> animation;
@override
Widget build(BuildContext context) {
return new AnimatedBuilder(
animation: animation,
builder: (BuildContext context, Widget child) {
return new Stack(
children: _kBackgroundLayers.map((_BackgroundLayer layer) {
return new Positioned(
top: -layer.parallaxTween.evaluate(animation),
left: 0.0,
right: 0.0,
bottom: 0.0,
child: new Image.asset(
layer.assetName,
package: layer.assetPackage,
fit: BoxFit.cover,
height: _kFlexibleSpaceMaxHeight
)
);
}).toList()
);
}
);
}
}
class GalleryHome extends StatefulWidget {
const GalleryHome({
Key key,
this.useLightTheme,
@required this.onThemeChanged,
this.timeDilation,
@required this.onTimeDilationChanged,
this.textScaleFactor,
this.onTextScaleFactorChanged,
this.showPerformanceOverlay,
this.onShowPerformanceOverlayChanged,
this.checkerboardRasterCacheImages,
this.onCheckerboardRasterCacheImagesChanged,
this.checkerboardOffscreenLayers,
this.onCheckerboardOffscreenLayersChanged,
this.onPlatformChanged,
this.onSendFeedback,
}) : assert(onThemeChanged != null),
assert(onTimeDilationChanged != null),
super(key: key);
final bool useLightTheme;
final ValueChanged<bool> onThemeChanged;
final double timeDilation;
final ValueChanged<double> onTimeDilationChanged;
final double textScaleFactor;
final ValueChanged<double> onTextScaleFactorChanged;
final bool showPerformanceOverlay;
final ValueChanged<bool> onShowPerformanceOverlayChanged;
final bool checkerboardRasterCacheImages;
final ValueChanged<bool> onCheckerboardRasterCacheImagesChanged;
final bool checkerboardOffscreenLayers;
final ValueChanged<bool> onCheckerboardOffscreenLayersChanged;
final ValueChanged<TargetPlatform> onPlatformChanged;
final VoidCallback onSendFeedback;
@override
GalleryHomeState createState() => new GalleryHomeState();
}
class GalleryHomeState extends State<GalleryHome> with SingleTickerProviderStateMixin {
static final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
AnimationController _controller;
@override
void initState() {
super.initState();
_controller = new AnimationController(
duration: const Duration(milliseconds: 600),
debugLabel: 'preview banner',
vsync: this,
)..forward();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
List<Widget> _galleryListItems() {
final List<Widget> listItems = <Widget>[];
final ThemeData themeData = Theme.of(context);
final TextStyle headerStyle = themeData.textTheme.body2.copyWith(color: themeData.accentColor);
String category;
for (GalleryItem galleryItem in kAllGalleryItems) {
if (category != galleryItem.category) {
if (category != null)
listItems.add(const Divider());
listItems.add(
new MergeSemantics(
child: new Container(
height: 48.0,
padding: const EdgeInsetsDirectional.only(start: 16.0),
alignment: AlignmentDirectional.centerStart,
child: new SafeArea(
top: false,
bottom: false,
child: new Text(galleryItem.category, style: headerStyle),
),
),
)
);
category = galleryItem.category;
}
listItems.add(galleryItem);
}
return listItems;
}
@override
Widget build(BuildContext context) {
Widget home = new Scaffold(
key: _scaffoldKey,
drawer: new GalleryDrawer(
useLightTheme: widget.useLightTheme,
onThemeChanged: widget.onThemeChanged,
timeDilation: widget.timeDilation,
onTimeDilationChanged: widget.onTimeDilationChanged,
textScaleFactor: widget.textScaleFactor,
onTextScaleFactorChanged: widget.onTextScaleFactorChanged,
showPerformanceOverlay: widget.showPerformanceOverlay,
onShowPerformanceOverlayChanged: widget.onShowPerformanceOverlayChanged,
checkerboardRasterCacheImages: widget.checkerboardRasterCacheImages,
onCheckerboardRasterCacheImagesChanged: widget.onCheckerboardRasterCacheImagesChanged,
checkerboardOffscreenLayers: widget.checkerboardOffscreenLayers,
onCheckerboardOffscreenLayersChanged: widget.onCheckerboardOffscreenLayersChanged,
onPlatformChanged: widget.onPlatformChanged,
onSendFeedback: widget.onSendFeedback,
),
body: new CustomScrollView(
slivers: <Widget>[
const SliverAppBar(
pinned: true,
expandedHeight: _kFlexibleSpaceMaxHeight,
flexibleSpace: const FlexibleSpaceBar(
title: const Text('Flutter Gallery'),
// TODO(abarth): Wire up to the parallax in a way that doesn't pop during hero transition.
background: const _AppBarBackground(animation: kAlwaysDismissedAnimation),
),
),
new SliverList(delegate: new SliverChildListDelegate(_galleryListItems())),
],
)
);
// In checked mode our MaterialApp will show the default "slow mode" banner.
// Otherwise show the "preview" banner.
bool showPreviewBanner = true;
assert(() {
showPreviewBanner = false;
return true;
}());
if (showPreviewBanner) {
home = new Stack(
fit: StackFit.expand,
children: <Widget>[
home,
new FadeTransition(
opacity: new CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
child: const Banner(
message: 'PREVIEW',
location: BannerLocation.topEnd,
)
),
]
);
}
return home;
}
}