List Gallery Demo
This commit is contained in:
parent
5ad80b776c
commit
25e22f5648
@ -33,7 +33,9 @@ material-design-icons:
|
||||
- name: action/hourglass_empty
|
||||
- name: action/info
|
||||
- name: action/language
|
||||
- name: action/list
|
||||
- name: av/play_arrow
|
||||
- name: av/sort_by_alpha
|
||||
- name: av/stop
|
||||
- name: communication/call
|
||||
- name: communication/email
|
||||
|
@ -23,7 +23,7 @@ class _ChipDemoState extends State<ChipDemo> {
|
||||
label: new Text('Apple')
|
||||
),
|
||||
new Chip(
|
||||
avatar: new CircleAvatar(label: 'B'),
|
||||
avatar: new CircleAvatar(child: new Text('B')),
|
||||
label: new Text('Blueberry')
|
||||
),
|
||||
];
|
||||
|
186
examples/material_gallery/lib/demo/list_demo.dart
Normal file
186
examples/material_gallery/lib/demo/list_demo.dart
Normal file
@ -0,0 +1,186 @@
|
||||
// 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/material.dart';
|
||||
|
||||
enum ListDemoItemSize {
|
||||
oneLine,
|
||||
twoLine,
|
||||
threeLine
|
||||
}
|
||||
|
||||
class ListDemo extends StatefulComponent {
|
||||
ListDemo({ Key key }) : super(key: key);
|
||||
|
||||
ListDemoState createState() => new ListDemoState();
|
||||
}
|
||||
|
||||
class ListDemoState extends State<ListDemo> {
|
||||
final GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();
|
||||
|
||||
ScaffoldFeatureController _bottomSheet;
|
||||
ListDemoItemSize _itemSize = ListDemoItemSize.threeLine;
|
||||
bool _isDense = true;
|
||||
bool _showAvatar = true;
|
||||
bool _showIcon = false;
|
||||
bool _reverseSort = false;
|
||||
List<String> items = <String>[
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N'
|
||||
];
|
||||
|
||||
void changeItemSize(ListDemoItemSize size) {
|
||||
setState(() {
|
||||
_itemSize = size;
|
||||
});
|
||||
_bottomSheet?.setState(() { });
|
||||
}
|
||||
|
||||
void showConfigurationSheet(BuildContext appContext) {
|
||||
_bottomSheet = scaffoldKey.currentState.showBottomSheet((BuildContext bottomSheetContext) {
|
||||
return new Container(
|
||||
decoration: new BoxDecoration(
|
||||
border: new Border(top: new BorderSide(color: Colors.black26, width: 1.0))
|
||||
),
|
||||
child: new Column(
|
||||
justifyContent: FlexJustifyContent.collapse,
|
||||
alignItems: FlexAlignItems.stretch,
|
||||
children: <Widget>[
|
||||
new ListItem(
|
||||
isDense: true,
|
||||
primary: new Text('One-line'),
|
||||
right: new Radio<ListDemoItemSize>(
|
||||
value: ListDemoItemSize.oneLine,
|
||||
groupValue: _itemSize,
|
||||
onChanged: changeItemSize
|
||||
)
|
||||
),
|
||||
new ListItem(
|
||||
isDense: true,
|
||||
primary: new Text('Two-line'),
|
||||
right: new Radio<ListDemoItemSize>(
|
||||
value: ListDemoItemSize.twoLine,
|
||||
groupValue: _itemSize,
|
||||
onChanged: changeItemSize
|
||||
)
|
||||
),
|
||||
new ListItem(
|
||||
isDense: true,
|
||||
primary: new Text('Three-line'),
|
||||
right: new Radio<ListDemoItemSize>(
|
||||
value: ListDemoItemSize.threeLine,
|
||||
groupValue: _itemSize,
|
||||
onChanged: changeItemSize
|
||||
)
|
||||
),
|
||||
new ListItem(
|
||||
isDense: true,
|
||||
primary: new Text('Show Avatar'),
|
||||
right: new Checkbox(
|
||||
value: _showAvatar,
|
||||
onChanged: (bool value) {
|
||||
setState(() {
|
||||
_showAvatar = value;
|
||||
});
|
||||
_bottomSheet?.setState(() { });
|
||||
}
|
||||
)
|
||||
),
|
||||
new ListItem(
|
||||
isDense: true,
|
||||
primary: new Text('Show Icon'),
|
||||
right: new Checkbox(
|
||||
value: _showIcon,
|
||||
onChanged: (bool value) {
|
||||
setState(() {
|
||||
_showIcon = value;
|
||||
});
|
||||
_bottomSheet?.setState(() { });
|
||||
}
|
||||
)
|
||||
),
|
||||
new ListItem(
|
||||
isDense: true,
|
||||
primary: new Text('Dense Layout'),
|
||||
right: new Checkbox(
|
||||
value: _isDense,
|
||||
onChanged: (bool value) {
|
||||
setState(() {
|
||||
_isDense = value;
|
||||
});
|
||||
_bottomSheet?.setState(() { });
|
||||
}
|
||||
)
|
||||
)
|
||||
]
|
||||
)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Widget buildListItem(BuildContext context, String item) {
|
||||
Widget secondary;
|
||||
if (_itemSize == ListDemoItemSize.twoLine) {
|
||||
secondary = new Text(
|
||||
"Additional item information."
|
||||
);
|
||||
} else if (_itemSize == ListDemoItemSize.threeLine) {
|
||||
secondary = new Text(
|
||||
"Even more additional list item information appears on line three."
|
||||
);
|
||||
}
|
||||
return new ListItem(
|
||||
isThreeLine: _itemSize == ListDemoItemSize.threeLine,
|
||||
isDense: _isDense,
|
||||
left: _showAvatar ? new CircleAvatar(child: new Text(item)) : null,
|
||||
primary: new Text('This item represents $item'),
|
||||
secondary: secondary,
|
||||
right: _showIcon ? new Icon(icon: 'action/info', color: Theme.of(context).disabledColor) : null
|
||||
);
|
||||
}
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
final String layoutText = _isDense ? " \u2013 Dense" : "";
|
||||
String itemSizeText;
|
||||
switch(_itemSize) {
|
||||
case ListDemoItemSize.oneLine:
|
||||
itemSizeText = 'Single-Line';
|
||||
break;
|
||||
case ListDemoItemSize.twoLine:
|
||||
itemSizeText = 'Two-Line';
|
||||
break;
|
||||
case ListDemoItemSize.threeLine:
|
||||
itemSizeText = 'Three-Line';
|
||||
break;
|
||||
}
|
||||
return new Scaffold(
|
||||
key: scaffoldKey,
|
||||
toolBar: new ToolBar(
|
||||
center: new Text('Scrolling List\n$itemSizeText$layoutText'),
|
||||
right: <Widget>[
|
||||
new IconButton(
|
||||
icon: "av/sort_by_alpha",
|
||||
tooltip: 'Sort',
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_reverseSort = !_reverseSort;
|
||||
items.sort((String a, String b) => _reverseSort ? b.compareTo(a) : a.compareTo(b));
|
||||
});
|
||||
}
|
||||
),
|
||||
new IconButton(
|
||||
icon: "navigation/more_vert",
|
||||
tooltip: 'Show menu',
|
||||
onPressed: () { showConfigurationSheet(context); }
|
||||
)
|
||||
]
|
||||
),
|
||||
body: new Padding(
|
||||
padding: const EdgeDims.all(8.0),
|
||||
child: new Block(
|
||||
children: items.map((String item) => buildListItem(context, item)).toList()
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -19,6 +19,7 @@ import '../demo/drop_down_demo.dart';
|
||||
import '../demo/fitness_demo.dart';
|
||||
import '../demo/grid_list_demo.dart';
|
||||
import '../demo/icons_demo.dart';
|
||||
import '../demo/list_demo.dart';
|
||||
import '../demo/modal_bottom_sheet_demo.dart';
|
||||
import '../demo/page_selector_demo.dart';
|
||||
import '../demo/persistent_bottom_sheet_demo.dart';
|
||||
@ -106,6 +107,7 @@ class GalleryHomeState extends State<GalleryHome> {
|
||||
new GalleryDemo(title: 'Floating Action Button', builder: () => new TabsFabDemo()),
|
||||
new GalleryDemo(title: 'Grid', builder: () => new GridListDemo()),
|
||||
new GalleryDemo(title: 'Icons', builder: () => new IconsDemo()),
|
||||
new GalleryDemo(title: 'List', builder: () => new ListDemo()),
|
||||
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()),
|
||||
|
@ -49,7 +49,7 @@ class GallerySection extends StatelessComponent {
|
||||
type: MaterialListType.oneLine,
|
||||
children: (demos ?? const <GalleryDemo>[]).map((GalleryDemo demo) {
|
||||
return new ListItem(
|
||||
center: new Text(demo.title, style: theme.text.subhead),
|
||||
primary: new Text(demo.title),
|
||||
onTap: () { showDemo(demo, context, theme); }
|
||||
);
|
||||
})
|
||||
|
@ -6,40 +6,36 @@ import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'constants.dart';
|
||||
import 'theme.dart';
|
||||
import 'typography.dart';
|
||||
|
||||
class CircleAvatar extends StatelessComponent {
|
||||
CircleAvatar({
|
||||
Key key,
|
||||
this.label,
|
||||
this.child,
|
||||
this.backgroundColor,
|
||||
this.textTheme
|
||||
this.radius: 40.0
|
||||
}) : super(key: key);
|
||||
|
||||
final String label;
|
||||
final Widget child;
|
||||
final Color backgroundColor;
|
||||
final TextTheme textTheme;
|
||||
final double radius;
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
Color color = backgroundColor;
|
||||
TextStyle style = textTheme?.title;
|
||||
|
||||
if (color == null || style == null) {
|
||||
ThemeData themeData = Theme.of(context);
|
||||
color ??= themeData.primaryColor;
|
||||
style ??= themeData.primaryTextTheme.title;
|
||||
}
|
||||
final ThemeData theme = Theme.of(context);
|
||||
final Color color = backgroundColor ?? theme.primaryColor;
|
||||
|
||||
return new AnimatedContainer(
|
||||
width: radius,
|
||||
height: radius,
|
||||
duration: kThemeChangeDuration,
|
||||
decoration: new BoxDecoration(
|
||||
backgroundColor: color,
|
||||
shape: BoxShape.circle
|
||||
),
|
||||
width: 40.0,
|
||||
height: 40.0,
|
||||
child: new Center(
|
||||
child: new Text(label, style: style)
|
||||
child: new DefaultTextStyle(
|
||||
style: theme.primaryTextTheme.title,
|
||||
child: child
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -5,53 +5,123 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'ink_well.dart';
|
||||
import 'theme.dart';
|
||||
|
||||
/// Material List items are one to three lines of text optionally flanked by icons.
|
||||
/// Icons are defined with the [left] and [right] parameters. The first line of text
|
||||
/// is not optional and is specified with [primary]. The value of [secondary] will
|
||||
/// occupy the space allocated for an aditional line of text, or two lines if
|
||||
/// isThreeLine: true is specified. If isDense: true is specified then the overall
|
||||
/// height of this list item and the size of the DefaultTextStyles that wrap
|
||||
/// the [primary] and [secondary] widget are reduced.
|
||||
class ListItem extends StatelessComponent {
|
||||
ListItem({
|
||||
Key key,
|
||||
this.left,
|
||||
this.center,
|
||||
this.primary,
|
||||
this.secondary,
|
||||
this.right,
|
||||
this.isThreeLine: false,
|
||||
this.isDense: false,
|
||||
this.onTap,
|
||||
this.onLongPress
|
||||
}) : super(key: key) {
|
||||
assert(center != null);
|
||||
assert(primary != null);
|
||||
assert(isThreeLine ? secondary != null : true);
|
||||
}
|
||||
|
||||
final Widget left;
|
||||
final Widget center;
|
||||
final Widget primary;
|
||||
final Widget secondary;
|
||||
final Widget right;
|
||||
final bool isThreeLine;
|
||||
final bool isDense;
|
||||
final GestureTapCallback onTap;
|
||||
final GestureLongPressCallback onLongPress;
|
||||
|
||||
TextStyle primaryTextStyle(BuildContext context) {
|
||||
final TextStyle style = Theme.of(context).text.subhead;
|
||||
return isDense ? style.copyWith(fontSize: 13.0) : style;
|
||||
}
|
||||
|
||||
TextStyle secondaryTextStyle(BuildContext context) {
|
||||
final ThemeData theme = Theme.of(context);
|
||||
final Color color = theme.text.caption.color;
|
||||
final TextStyle style = theme.text.body1;
|
||||
return isDense ? style.copyWith(color: color, fontSize: 12.0) : style.copyWith(color: color);
|
||||
}
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
List<Widget> children = new List<Widget>();
|
||||
final bool isTwoLine = !isThreeLine && secondary != null;
|
||||
final bool isOneLine = !isThreeLine && !isTwoLine;
|
||||
double itemHeight;
|
||||
if (isOneLine)
|
||||
itemHeight = isDense ? 48.0 : 56.0;
|
||||
else if (isTwoLine)
|
||||
itemHeight = isDense ? 60.0 : 72.0;
|
||||
else
|
||||
itemHeight = isDense ? 76.0 : 88.0;
|
||||
|
||||
double iconMarginTop = 0.0;
|
||||
if (isThreeLine)
|
||||
iconMarginTop = isDense ? 8.0 : 16.0;
|
||||
|
||||
// Overall, the list item is a Row() with these children.
|
||||
final List<Widget> children = <Widget>[];
|
||||
|
||||
if (left != null) {
|
||||
children.add(new Container(
|
||||
margin: new EdgeDims.only(right: 16.0),
|
||||
margin: new EdgeDims.only(right: 16.0, top: iconMarginTop),
|
||||
width: 40.0,
|
||||
child: left
|
||||
child: new Align(
|
||||
alignment: new FractionalOffset(0.0, isThreeLine ? 0.0 : 0.5),
|
||||
child: left
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
final Widget primaryLine = new DefaultTextStyle(
|
||||
style: primaryTextStyle(context),
|
||||
child: primary
|
||||
);
|
||||
Widget center = primaryLine;
|
||||
if (isTwoLine || isThreeLine) {
|
||||
center = new Column(
|
||||
justifyContent: FlexJustifyContent.collapse,
|
||||
alignItems: FlexAlignItems.start,
|
||||
children: <Widget>[
|
||||
primaryLine,
|
||||
new DefaultTextStyle(
|
||||
style: secondaryTextStyle(context),
|
||||
child: secondary
|
||||
)
|
||||
]
|
||||
);
|
||||
}
|
||||
children.add(new Flexible(
|
||||
child: center
|
||||
));
|
||||
|
||||
if (right != null) {
|
||||
children.add(new Container(
|
||||
margin: new EdgeDims.only(left: 16.0),
|
||||
child: right
|
||||
margin: new EdgeDims.only(left: 16.0, top: iconMarginTop),
|
||||
child: new Align(
|
||||
alignment: new FractionalOffset(1.0, isThreeLine ? 0.0 : 0.5),
|
||||
child: right
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
return new InkWell(
|
||||
onTap: onTap,
|
||||
onLongPress: onLongPress,
|
||||
child: new Padding(
|
||||
child: new Container(
|
||||
height: itemHeight,
|
||||
padding: const EdgeDims.symmetric(horizontal: 16.0),
|
||||
child: new Row(children: children)
|
||||
child: new Row(
|
||||
alignItems: FlexAlignItems.center,
|
||||
children: children
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -332,7 +332,7 @@ class ScaffoldState extends State<Scaffold> {
|
||||
bottomSheet,
|
||||
completer,
|
||||
() => entry.remove(),
|
||||
setState
|
||||
(VoidCallback fn) { bottomSheetKey.currentState?.setState(fn); }
|
||||
);
|
||||
});
|
||||
return _currentBottomSheet;
|
||||
|
@ -39,7 +39,7 @@ class TwoLevelListItem extends StatelessComponent {
|
||||
height: kListItemExtent[parentList.type],
|
||||
child: new ListItem(
|
||||
left: left,
|
||||
center: center,
|
||||
primary: center,
|
||||
right: right,
|
||||
onTap: onTap,
|
||||
onLongPress: onLongPress
|
||||
|
Loading…
x
Reference in New Issue
Block a user