Commit 7915e909 authored by Hans Muller's avatar Hans Muller

Merge pull request #2110 from HansMuller/list_demo

Gallery List Demo
parents 5ad80b77 25e22f56
......@@ -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')
),
];
......
// 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
......
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