Added GridTileBar, grid gallery demo
This commit is contained in:
parent
f073f6b5a3
commit
8cfe31f5e8
@ -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
|
||||
|
224
examples/material_gallery/lib/demo/grid_list_demo.dart
Normal file
224
examples/material_gallery/lib/demo/grid_list_demo.dart
Normal file
@ -0,0 +1,224 @@
|
||||
// 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';
|
||||
|
88
packages/flutter/lib/src/material/grid_tile_bar.dart
Normal file
88
packages/flutter/lib/src/material/grid_tile_bar.dart
Normal file
@ -0,0 +1,88 @@
|
||||
// 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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user