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/face
|
||||||
- name: action/home
|
- name: action/home
|
||||||
- name: action/hourglass_empty
|
- name: action/hourglass_empty
|
||||||
|
- name: action/info
|
||||||
- name: action/language
|
- name: action/language
|
||||||
- name: av/play_arrow
|
- name: av/play_arrow
|
||||||
- name: av/stop
|
- 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/date_picker_demo.dart';
|
||||||
import '../demo/dialog_demo.dart';
|
import '../demo/dialog_demo.dart';
|
||||||
import '../demo/drop_down_demo.dart';
|
import '../demo/drop_down_demo.dart';
|
||||||
|
import '../demo/grid_list_demo.dart';
|
||||||
import '../demo/modal_bottom_sheet_demo.dart';
|
import '../demo/modal_bottom_sheet_demo.dart';
|
||||||
import '../demo/page_selector_demo.dart';
|
import '../demo/page_selector_demo.dart';
|
||||||
import '../demo/persistent_bottom_sheet_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: 'Dropdown Button', builder: () => new DropDownDemo()),
|
||||||
new GalleryDemo(title: 'Expland/Collapse List Control', builder: () => new TwoLevelListDemo()),
|
new GalleryDemo(title: 'Expland/Collapse List Control', builder: () => new TwoLevelListDemo()),
|
||||||
new GalleryDemo(title: 'Floating Action Button', builder: () => new TabsFabDemo()),
|
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: 'Modal Bottom Sheet', builder: () => new ModalBottomSheetDemo()),
|
||||||
new GalleryDemo(title: 'Page Selector', builder: () => new PageSelectorDemo()),
|
new GalleryDemo(title: 'Page Selector', builder: () => new PageSelectorDemo()),
|
||||||
new GalleryDemo(title: 'Persistent Bottom Sheet', builder: () => new PersistentBottomSheetDemo()),
|
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/flat_button.dart';
|
||||||
export 'src/material/flexible_space_bar.dart';
|
export 'src/material/flexible_space_bar.dart';
|
||||||
export 'src/material/floating_action_button.dart';
|
export 'src/material/floating_action_button.dart';
|
||||||
|
export 'src/material/grid_tile_bar.dart';
|
||||||
export 'src/material/icon.dart';
|
export 'src/material/icon.dart';
|
||||||
export 'src/material/icon_button.dart';
|
export 'src/material/icon_button.dart';
|
||||||
export 'src/material/icon_theme.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,
|
FlexJustifyContent,
|
||||||
FractionalOffsetTween,
|
FractionalOffsetTween,
|
||||||
GridDelegate,
|
GridDelegate,
|
||||||
|
GridDelegateWithInOrderChildPlacement,
|
||||||
GridSpecification,
|
GridSpecification,
|
||||||
HitTestBehavior,
|
HitTestBehavior,
|
||||||
MaxTileWidthGridDelegate,
|
MaxTileWidthGridDelegate,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user