Commit 8cfe31f5 authored by Hans Muller's avatar Hans Muller

Added GridTileBar, grid gallery demo

parent f073f6b5
......@@ -31,6 +31,7 @@ material-design-icons:
- name: action/face
- name: action/home
- name: action/hourglass_empty
- name: action/info
- name: action/language
- name: av/play_arrow
- name: av/stop
......
// 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 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
enum GridDemoTileStyle {
imageOnly,
oneLine,
twoLine
}
class Photo {
const Photo({ this.assetName });
final String assetName;
String get title => 'Safari';
String get caption => 'March 2015';
bool get isValid => assetName != null;
}
final List<Photo> photos = new List<Photo>.generate(16, (int index) {
return const Photo(assetName: 'packages/flutter_gallery_assets/kangaroo_valley_safari.png');
});
class GridDemoPhotoItem extends StatelessComponent {
GridDemoPhotoItem({ Key key, this.photo, this.tileStyle }) : super(key: key) {
assert(photo != null && photo.isValid);
assert(tileStyle != null);
}
final Photo photo;
final GridDemoTileStyle tileStyle;
void showPhoto(BuildContext context) {
Navigator.push(context, new MaterialPageRoute(
builder: (BuildContext context) {
return new Scaffold(
toolBar: new ToolBar(
center: new Text(photo.title)
),
body: new Material(
child: new AssetImage(
name: photo.assetName,
fit: ImageFit.cover
)
)
);
}
));
}
Widget build(BuildContext context) {
final Widget image = new GestureDetector(
onTap: () { showPhoto(context); },
child: new AssetImage(
name: photo.assetName,
fit: ImageFit.cover
)
);
switch(tileStyle) {
case GridDemoTileStyle.imageOnly:
return image;
case GridDemoTileStyle.oneLine:
return new Stack(
children: <Widget>[
new Positioned(
top: 0.0,
left: 0.0,
bottom: 0.0,
right: 0.0,
child: image
),
new Positioned(
top: 0.0,
left: 0.0,
right: 0.0,
child: new GridTileBar(
backgroundColor: Colors.black.withAlpha(0x08),
title: new Text(photo.title),
left: new Icon(icon: 'action/info', color: Colors.white70)
)
)
]
);
case GridDemoTileStyle.twoLine:
return new Stack(
children: <Widget>[
new Positioned(
top: 0.0,
left: 0.0,
bottom: 0.0,
right: 0.0,
child: image
),
new Positioned(
left: 0.0,
bottom: 0.0,
right: 0.0,
child: new GridTileBar(
backgroundColor: Colors.black.withAlpha(0x08),
title: new Text(photo.title),
caption: new Text(photo.caption),
right: new Icon(icon: 'action/info', color: Colors.white70)
)
)
]
);
}
}
}
class GridListDemoGridDelegate extends FixedColumnCountGridDelegate {
GridListDemoGridDelegate({
this.columnCount,
double columnSpacing: 0.0,
double rowSpacing: 0.0,
EdgeDims padding: EdgeDims.zero,
this.tileHeightFactor: 2.75
}) : super(columnSpacing: columnSpacing, rowSpacing: rowSpacing, padding: padding) {
assert(columnCount != null && columnCount >= 0);
assert(tileHeightFactor != null && tileHeightFactor > 0.0);
}
final int columnCount;
final double tileHeightFactor;
GridSpecification getGridSpecification(BoxConstraints constraints, int childCount) {
assert(constraints.maxWidth < double.INFINITY);
assert(constraints.maxHeight < double.INFINITY);
return new GridSpecification.fromRegularTiles(
tileWidth: math.max(0.0, constraints.maxWidth - padding.horizontal + columnSpacing) / columnCount,
tileHeight: constraints.maxHeight / tileHeightFactor,
columnCount: columnCount,
rowCount: (childCount / columnCount).ceil(),
columnSpacing: columnSpacing,
rowSpacing: rowSpacing,
padding: padding
);
}
bool shouldRelayout(GridListDemoGridDelegate oldDelegate) {
return columnCount != oldDelegate.columnCount
|| tileHeightFactor != oldDelegate.tileHeightFactor
|| super.shouldRelayout(oldDelegate);
}
}
class GridListDemo extends StatefulComponent {
GridListDemoState createState() => new GridListDemoState();
}
class GridListDemoState extends State<GridListDemo> {
GridDemoTileStyle tileStyle = GridDemoTileStyle.twoLine;
void showTileStyleMenu(BuildContext context) {
final List<PopupMenuItem> items = <PopupMenuItem>[
new PopupMenuItem(
value: GridDemoTileStyle.imageOnly,
child: new Text('Image only')
),
new PopupMenuItem(
value: GridDemoTileStyle.oneLine,
child: new Text('One line')
),
new PopupMenuItem(
value: GridDemoTileStyle.twoLine,
child: new Text('Two line')
)
];
final EdgeDims padding = MediaQuery.of(context).padding;
final ModalPosition position = new ModalPosition(
right: padding.right + 16.0,
top: padding.top + 16.0
);
showMenu(context: context, position: position, items: items).then((GridDemoTileStyle value) {
setState(() {
tileStyle = value;
});
});
}
// When the ScrollableGrid first appears we want the last row to only be
// partially visible, to help the user recognize that the grid is scrollable.
// The GridListDemoGridDelegate's tileHeightFactor is used for this.
Widget build(BuildContext context) {
final Orientation orientation = MediaQuery.of(context).orientation;
return new Scaffold(
toolBar: new ToolBar(
center: new Text('Grid List'),
right: <Widget>[
new IconButton(
icon: "navigation/more_vert",
onPressed: () { showTileStyleMenu(context); },
tooltip: 'Show menu'
)
]
),
body: new ScrollableGrid(
delegate: new GridListDemoGridDelegate(
columnCount: (orientation == Orientation.portrait) ? 2 : 3,
rowSpacing: 4.0,
columnSpacing: 4.0,
padding: const EdgeDims.all(4.0),
tileHeightFactor: (orientation == Orientation.portrait) ? 2.75 : 1.75
),
children: photos.map((Photo photo) {
return new GridDemoPhotoItem(photo: photo, tileStyle: tileStyle);
})
.toList()
)
);
}
}
......@@ -16,6 +16,7 @@ import '../demo/chip_demo.dart';
import '../demo/date_picker_demo.dart';
import '../demo/dialog_demo.dart';
import '../demo/drop_down_demo.dart';
import '../demo/grid_list_demo.dart';
import '../demo/modal_bottom_sheet_demo.dart';
import '../demo/page_selector_demo.dart';
import '../demo/persistent_bottom_sheet_demo.dart';
......@@ -101,6 +102,7 @@ class GalleryHomeState extends State<GalleryHome> {
new GalleryDemo(title: 'Dropdown Button', builder: () => new DropDownDemo()),
new GalleryDemo(title: 'Expland/Collapse List Control', builder: () => new TwoLevelListDemo()),
new GalleryDemo(title: 'Floating Action Button', builder: () => new TabsFabDemo()),
new GalleryDemo(title: 'Grid', builder: () => new GridListDemo()),
new GalleryDemo(title: 'Modal Bottom Sheet', builder: () => new ModalBottomSheetDemo()),
new GalleryDemo(title: 'Page Selector', builder: () => new PageSelectorDemo()),
new GalleryDemo(title: 'Persistent Bottom Sheet', builder: () => new PersistentBottomSheetDemo()),
......
......@@ -25,6 +25,7 @@ export 'src/material/dropdown.dart';
export 'src/material/flat_button.dart';
export 'src/material/flexible_space_bar.dart';
export 'src/material/floating_action_button.dart';
export 'src/material/grid_tile_bar.dart';
export 'src/material/icon.dart';
export 'src/material/icon_button.dart';
export 'src/material/icon_theme.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/widgets.dart';
import 'icon_theme.dart';
import 'icon_theme_data.dart';
import 'typography.dart';
/// Typically used to stack a one or two line header or footer on a Grid tile.
/// The layout is based on the "Grid Lists" section of the Material Design spec:
/// https://www.google.com/design/spec/components/grid-lists.html#grid-lists-specs
/// For a one-line header specify title and to add a second line specify caption.
/// Use left or right to add an icon.
class GridTileBar extends StatelessComponent {
GridTileBar({ Key key, this.backgroundColor, this.left, this.right, this.title, this.caption }) : super(key: key);
final Color backgroundColor;
final Widget left;
final Widget right;
final Widget title;
final Widget caption;
Widget build(BuildContext context) {
BoxDecoration decoration;
if (backgroundColor != null)
decoration = new BoxDecoration(backgroundColor: backgroundColor);
EdgeDims padding;
if (left != null && right != null)
padding = const EdgeDims.symmetric(vertical: 16.0, horizontal: 8.0);
else if (left != null)
padding = const EdgeDims.only(left: 8.0, right: 16.0, top: 16.0, bottom: 16.0);
else // right != null || (left == null && right == null)
padding = const EdgeDims.only(left: 16.0, right: 8.0, top: 16.0, bottom: 16.0);
final List<Widget> children = <Widget>[];
if (left != null)
children.add(new Padding(padding: const EdgeDims.only(right: 8.0), child: left));
if (title != null && caption != null) {
children.add(
new Flexible(
child: new Column(
alignItems: FlexAlignItems.start,
children: <Widget>[
new DefaultTextStyle(
style: Typography.white.subhead,
child: title
),
new DefaultTextStyle(
style: Typography.white.caption,
child: caption
)
]
)
)
);
} else if (title != null || caption != null) {
children.add(
new Flexible(
child: new DefaultTextStyle(
style: Typography.white.subhead,
child: title ?? caption
)
)
);
}
if (right != null)
children.add(new Padding(padding: const EdgeDims.only(left: 8.0), child: right));
return new Container(
padding: padding,
decoration: decoration,
child: new IconTheme(
data: new IconThemeData(color: IconThemeColor.white),
child: new Row(
alignItems: FlexAlignItems.center,
children: children
)
)
);
}
}
......@@ -22,6 +22,7 @@ export 'package:flutter/rendering.dart' show
FlexJustifyContent,
FractionalOffsetTween,
GridDelegate,
GridDelegateWithInOrderChildPlacement,
GridSpecification,
HitTestBehavior,
MaxTileWidthGridDelegate,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment