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/hourglass_empty
|
||||||
- name: action/info
|
- name: action/info
|
||||||
- name: action/language
|
- name: action/language
|
||||||
|
- name: action/list
|
||||||
- name: av/play_arrow
|
- name: av/play_arrow
|
||||||
|
- name: av/sort_by_alpha
|
||||||
- name: av/stop
|
- name: av/stop
|
||||||
- name: communication/call
|
- name: communication/call
|
||||||
- name: communication/email
|
- name: communication/email
|
||||||
|
@ -23,7 +23,7 @@ class _ChipDemoState extends State<ChipDemo> {
|
|||||||
label: new Text('Apple')
|
label: new Text('Apple')
|
||||||
),
|
),
|
||||||
new Chip(
|
new Chip(
|
||||||
avatar: new CircleAvatar(label: 'B'),
|
avatar: new CircleAvatar(child: new Text('B')),
|
||||||
label: new Text('Blueberry')
|
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/fitness_demo.dart';
|
||||||
import '../demo/grid_list_demo.dart';
|
import '../demo/grid_list_demo.dart';
|
||||||
import '../demo/icons_demo.dart';
|
import '../demo/icons_demo.dart';
|
||||||
|
import '../demo/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';
|
||||||
@ -106,6 +107,7 @@ class GalleryHomeState extends State<GalleryHome> {
|
|||||||
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: 'Grid', builder: () => new GridListDemo()),
|
||||||
new GalleryDemo(title: 'Icons', builder: () => new IconsDemo()),
|
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: '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()),
|
||||||
|
@ -49,7 +49,7 @@ class GallerySection extends StatelessComponent {
|
|||||||
type: MaterialListType.oneLine,
|
type: MaterialListType.oneLine,
|
||||||
children: (demos ?? const <GalleryDemo>[]).map((GalleryDemo demo) {
|
children: (demos ?? const <GalleryDemo>[]).map((GalleryDemo demo) {
|
||||||
return new ListItem(
|
return new ListItem(
|
||||||
center: new Text(demo.title, style: theme.text.subhead),
|
primary: new Text(demo.title),
|
||||||
onTap: () { showDemo(demo, context, theme); }
|
onTap: () { showDemo(demo, context, theme); }
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
|
@ -6,40 +6,36 @@ import 'package:flutter/widgets.dart';
|
|||||||
|
|
||||||
import 'constants.dart';
|
import 'constants.dart';
|
||||||
import 'theme.dart';
|
import 'theme.dart';
|
||||||
import 'typography.dart';
|
|
||||||
|
|
||||||
class CircleAvatar extends StatelessComponent {
|
class CircleAvatar extends StatelessComponent {
|
||||||
CircleAvatar({
|
CircleAvatar({
|
||||||
Key key,
|
Key key,
|
||||||
this.label,
|
this.child,
|
||||||
this.backgroundColor,
|
this.backgroundColor,
|
||||||
this.textTheme
|
this.radius: 40.0
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final String label;
|
final Widget child;
|
||||||
final Color backgroundColor;
|
final Color backgroundColor;
|
||||||
final TextTheme textTheme;
|
final double radius;
|
||||||
|
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Color color = backgroundColor;
|
final ThemeData theme = Theme.of(context);
|
||||||
TextStyle style = textTheme?.title;
|
final Color color = backgroundColor ?? theme.primaryColor;
|
||||||
|
|
||||||
if (color == null || style == null) {
|
|
||||||
ThemeData themeData = Theme.of(context);
|
|
||||||
color ??= themeData.primaryColor;
|
|
||||||
style ??= themeData.primaryTextTheme.title;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new AnimatedContainer(
|
return new AnimatedContainer(
|
||||||
|
width: radius,
|
||||||
|
height: radius,
|
||||||
duration: kThemeChangeDuration,
|
duration: kThemeChangeDuration,
|
||||||
decoration: new BoxDecoration(
|
decoration: new BoxDecoration(
|
||||||
backgroundColor: color,
|
backgroundColor: color,
|
||||||
shape: BoxShape.circle
|
shape: BoxShape.circle
|
||||||
),
|
),
|
||||||
width: 40.0,
|
|
||||||
height: 40.0,
|
|
||||||
child: new Center(
|
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 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
import 'ink_well.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 {
|
class ListItem extends StatelessComponent {
|
||||||
ListItem({
|
ListItem({
|
||||||
Key key,
|
Key key,
|
||||||
this.left,
|
this.left,
|
||||||
this.center,
|
this.primary,
|
||||||
|
this.secondary,
|
||||||
this.right,
|
this.right,
|
||||||
|
this.isThreeLine: false,
|
||||||
|
this.isDense: false,
|
||||||
this.onTap,
|
this.onTap,
|
||||||
this.onLongPress
|
this.onLongPress
|
||||||
}) : super(key: key) {
|
}) : super(key: key) {
|
||||||
assert(center != null);
|
assert(primary != null);
|
||||||
|
assert(isThreeLine ? secondary != null : true);
|
||||||
}
|
}
|
||||||
|
|
||||||
final Widget left;
|
final Widget left;
|
||||||
final Widget center;
|
final Widget primary;
|
||||||
|
final Widget secondary;
|
||||||
final Widget right;
|
final Widget right;
|
||||||
|
final bool isThreeLine;
|
||||||
|
final bool isDense;
|
||||||
final GestureTapCallback onTap;
|
final GestureTapCallback onTap;
|
||||||
final GestureLongPressCallback onLongPress;
|
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) {
|
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) {
|
if (left != null) {
|
||||||
children.add(new Container(
|
children.add(new Container(
|
||||||
margin: new EdgeDims.only(right: 16.0),
|
margin: new EdgeDims.only(right: 16.0, top: iconMarginTop),
|
||||||
width: 40.0,
|
width: 40.0,
|
||||||
|
child: new Align(
|
||||||
|
alignment: new FractionalOffset(0.0, isThreeLine ? 0.0 : 0.5),
|
||||||
child: left
|
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(
|
children.add(new Flexible(
|
||||||
child: center
|
child: center
|
||||||
));
|
));
|
||||||
|
|
||||||
if (right != null) {
|
if (right != null) {
|
||||||
children.add(new Container(
|
children.add(new Container(
|
||||||
margin: new EdgeDims.only(left: 16.0),
|
margin: new EdgeDims.only(left: 16.0, top: iconMarginTop),
|
||||||
|
child: new Align(
|
||||||
|
alignment: new FractionalOffset(1.0, isThreeLine ? 0.0 : 0.5),
|
||||||
child: right
|
child: right
|
||||||
|
)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new InkWell(
|
return new InkWell(
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
onLongPress: onLongPress,
|
onLongPress: onLongPress,
|
||||||
child: new Padding(
|
child: new Container(
|
||||||
|
height: itemHeight,
|
||||||
padding: const EdgeDims.symmetric(horizontal: 16.0),
|
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,
|
bottomSheet,
|
||||||
completer,
|
completer,
|
||||||
() => entry.remove(),
|
() => entry.remove(),
|
||||||
setState
|
(VoidCallback fn) { bottomSheetKey.currentState?.setState(fn); }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
return _currentBottomSheet;
|
return _currentBottomSheet;
|
||||||
|
@ -39,7 +39,7 @@ class TwoLevelListItem extends StatelessComponent {
|
|||||||
height: kListItemExtent[parentList.type],
|
height: kListItemExtent[parentList.type],
|
||||||
child: new ListItem(
|
child: new ListItem(
|
||||||
left: left,
|
left: left,
|
||||||
center: center,
|
primary: center,
|
||||||
right: right,
|
right: right,
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
onLongPress: onLongPress
|
onLongPress: onLongPress
|
||||||
|
Loading…
x
Reference in New Issue
Block a user