Commit ec4a6a96 authored by Adam Barth's avatar Adam Barth

Add more dartdocs to material.dart (#3279)

parent 8d02f304
......@@ -193,7 +193,7 @@ class ListDemoState extends State<ListDemo> {
child: new Scrollbar(
child: new MaterialList(
type: _itemType,
scrollablePadding: new EdgeInsets.all(_dense ? 4.0 : 8.0),
padding: new EdgeInsets.all(_dense ? 4.0 : 8.0),
children: listItems
)
)
......
......@@ -11,7 +11,7 @@ class TwoLevelListDemo extends StatelessWidget {
appBar: new AppBar(title: new Text('Expand/collapse list control')),
body: new TwoLevelList(
type: MaterialListType.oneLine,
items: <Widget>[
children: <Widget>[
new TwoLevelListItem(title: new Text('Top')),
new TwoLevelSublist(
title: new Text('Sublist'),
......
......@@ -91,10 +91,10 @@ class GalleryHomeState extends State<GalleryHome> {
scrollableKey: _listKey,
appBarBehavior: AppBarBehavior.under,
body: new TwoLevelList(
scrollablePadding: new EdgeInsets.only(top: _kFlexibleSpaceMaxHeight + statusBarHight),
padding: new EdgeInsets.only(top: _kFlexibleSpaceMaxHeight + statusBarHight),
type: MaterialListType.oneLine,
scrollableKey: _listKey,
items: <Widget>[
children: <Widget>[
new TwoLevelSublist(
leading: new Icon(icon: Icons.star),
title: new Text("Demos"),
......
......@@ -4,13 +4,36 @@
import 'package:flutter/widgets.dart';
/// The kind of list items contained in a material design list.
///
/// See also:
///
/// * [MaterialList]
/// * [ListItem]
/// * [kListItemExtent]
/// * <https://www.google.com/design/spec/components/lists.html#lists-specs>
enum MaterialListType {
/// A list item that contains a single line of text.
oneLine,
/// A list item that contains a [CircleAvatar] followed by a single line of text.
oneLineWithAvatar,
/// A list item that contains two lines of text.
twoLine,
/// A list item that contains three lines of text.
threeLine
}
/// The vertical extent of the different types of material list items.
///
/// See also:
///
/// * [MaterialListType]
/// * [ListItem]
/// * [kListItemExtent]
/// * <https://www.google.com/design/spec/components/lists.html#lists-specs>
Map<MaterialListType, double> kListItemExtent = const <MaterialListType, double>{
MaterialListType.oneLine: 48.0,
MaterialListType.oneLineWithAvatar: 56.0,
......@@ -18,39 +41,70 @@ Map<MaterialListType, double> kListItemExtent = const <MaterialListType, double>
MaterialListType.threeLine: 88.0,
};
class MaterialList extends StatefulWidget {
/// A scrollable list containing material list items.
///
/// Material list configures a [ScrollableList] with a number of default values
/// to match material design.
///
/// See also:
///
/// * [ListItem]
/// * [ScrollableList]
/// * [TwoLevelList]
/// * [ScrollableGrid]
/// * <https://www.google.com/design/spec/components/lists.html>
class MaterialList extends StatelessWidget {
/// Creates a material list.
///
/// By default, has a type of [MaterialListType.twoLine].
MaterialList({
Key key,
this.initialScrollOffset,
this.onScrollStart,
this.onScroll,
this.onScrollEnd,
this.type: MaterialListType.twoLine,
this.children,
this.scrollablePadding: EdgeInsets.zero,
this.padding: EdgeInsets.zero,
this.scrollableKey
}) : super(key: key);
/// The scroll offset this widget should use when first created.
final double initialScrollOffset;
/// Called whenever this widget starts to scroll.
final ScrollListener onScrollStart;
/// Called whenever this widget's scroll offset changes.
final ScrollListener onScroll;
/// Called whenever this widget stops scrolling.
final ScrollListener onScrollEnd;
/// The kind of [ListItem] contained in this list.
final MaterialListType type;
/// The widgets to display in this list.
final Iterable<Widget> children;
final EdgeInsets scrollablePadding;
final Key scrollableKey;
@override
_MaterialListState createState() => new _MaterialListState();
}
/// The amount of space by which to inset the children inside the viewport.
final EdgeInsets padding;
/// The key to use for the underlying scrollable widget.
final Key scrollableKey;
class _MaterialListState extends State<MaterialList> {
@override
Widget build(BuildContext context) {
return new ScrollableList(
key: config.scrollableKey,
initialScrollOffset: config.initialScrollOffset,
key: scrollableKey,
initialScrollOffset: initialScrollOffset,
scrollDirection: Axis.vertical,
onScroll: config.onScroll,
itemExtent: kListItemExtent[config.type],
padding: const EdgeInsets.symmetric(vertical: 8.0) + config.scrollablePadding,
children: config.children
onScrollStart: onScrollStart,
onScroll: onScroll,
onScrollEnd: onScrollEnd,
itemExtent: kListItemExtent[type],
padding: const EdgeInsets.symmetric(vertical: 8.0) + padding,
children: children
);
}
}
......@@ -118,7 +118,7 @@ class ListItem extends StatelessWidget {
yield item;
}
TextStyle primaryTextStyle(BuildContext context) {
TextStyle _primaryTextStyle(BuildContext context) {
final ThemeData theme = Theme.of(context);
final TextStyle style = theme.textTheme.subhead;
if (!enabled) {
......@@ -128,7 +128,7 @@ class ListItem extends StatelessWidget {
return dense ? style.copyWith(fontSize: 13.0) : style;
}
TextStyle secondaryTextStyle(BuildContext context) {
TextStyle _secondaryTextStyle(BuildContext context) {
final ThemeData theme = Theme.of(context);
final Color color = theme.textTheme.caption.color;
final TextStyle style = theme.textTheme.body1;
......@@ -167,7 +167,7 @@ class ListItem extends StatelessWidget {
}
final Widget primaryLine = new DefaultTextStyle(
style: primaryTextStyle(context),
style: _primaryTextStyle(context),
child: title ?? new Container()
);
Widget center = primaryLine;
......@@ -178,7 +178,7 @@ class ListItem extends StatelessWidget {
children: <Widget>[
primaryLine,
new DefaultTextStyle(
style: secondaryTextStyle(context),
style: _secondaryTextStyle(context),
child: subtitle
)
]
......
......@@ -12,6 +12,11 @@ import 'constants.dart';
import 'shadows.dart';
import 'theme.dart';
/// The various kinds of material in material design.
///
/// See also:
/// * [Material]
/// * [kMaterialEdges]
enum MaterialType {
/// Infinite extent using default theme canvas color.
canvas,
......@@ -29,6 +34,12 @@ enum MaterialType {
transparency
}
/// The border radii used by the various kinds of material in material design.
///
/// See also:
///
/// * [MaterialType]
/// * [Material]
const Map<MaterialType, double> kMaterialEdges = const <MaterialType, double>{
MaterialType.canvas: null,
MaterialType.card: 2.0,
......@@ -37,23 +48,50 @@ const Map<MaterialType, double> kMaterialEdges = const <MaterialType, double>{
MaterialType.transparency: null,
};
/// A visual reaction on a piece of [Material] to user input.
///
/// Typically created by [MaterialInkController.splashAt].
abstract class InkSplash {
/// The user input is confirmed.
///
/// Causes the reaction to propagate faster across the material.
void confirm();
/// The user input was cancelled.
///
/// Causes the reaction to gradually disappear.
void cancel();
/// Free up the resources associated with this reaction.
void dispose();
}
/// A visual emphasis on a part of a [Material] receiving user interaction.
///
/// Typically created by [MaterialInkController.highlightAt].
abstract class InkHighlight {
/// Start visually emphasizing this part of the material.
void activate();
/// Stop visually emphasizing this part of the material.
void deactivate();
/// Free up the resources associated with this highlight.
void dispose();
/// Whether this part of the material is being visually emphasized.
bool get active;
/// The color use to visually represent the emphasis.
Color get color;
void set color(Color value);
}
/// An interface for creating [InkSplash]s and [InkHighlight]s on a material.
///
/// Typically obtained via [Material.of].
abstract class MaterialInkController {
/// The color of the material
/// The color of the material.
Color get color;
/// Begin a splash, centered at position relative to referenceBox.
......@@ -69,11 +107,31 @@ abstract class MaterialInkController {
void addInkFeature(InkFeature feature);
}
/// Describes a sheet of Material. If the layout changes (e.g. because there's a
/// list on the paper, and it's been scrolled), a LayoutChangedNotification must
/// be dispatched at the relevant subtree. (This in particular means that
/// Transitions should not be placed inside Material.)
/// A piece of material.
///
/// Material is the central metaphor in material design. Each piece of material
/// exists at a given elevation, which influences how that piece of material
/// visually relates to other pieces of material and how that material casts
/// shadows on other pieces of material.
///
/// Most user interface elements are either conceptually printed on a piece of
/// material or themselves made of material. Material reacts to user input using
/// [InkSplash] and [InkHighlight] effects. To trigger a reaction on the
/// material, use a [MaterialInkController] obtained via [Material.of].
///
/// If the layout changes (e.g. because there's a list on the paper, and it's
/// been scrolled), a LayoutChangedNotification must be dispatched at the
/// relevant subtree. (This in particular means that Transitions should not be
/// placed inside Material.) Otherwise, in-progress ink features (e.g., ink
/// splashes and ink highlights) won't move to account for the new layout.
///
/// See also:
///
/// * <https://www.google.com/design/spec/material-design/introduction.html>
class Material extends StatefulWidget {
/// Creates a piece of material.
///
/// Both the type and the elevation arguments are required.
Material({
Key key,
this.child,
......@@ -89,18 +147,24 @@ class Material extends StatefulWidget {
/// The widget below this widget in the tree.
final Widget child;
/// The kind of material (e.g., card or canvas).
final MaterialType type;
/// The z-coordinate at which to place this material.
final int elevation;
/// The color of the material.
///
/// Must be opaque. To create a transparent piece of material, use
/// [MaterialType.transparency].
final Color color;
/// The typographical style to use for text within this material.
final TextStyle textStyle;
/// The ink controller from the closest instance of this class that encloses the given context.
static MaterialInkController of(BuildContext context) {
final RenderInkFeatures result = context.ancestorRenderObjectOfType(const TypeMatcher<RenderInkFeatures>());
final _RenderInkFeatures result = context.ancestorRenderObjectOfType(const TypeMatcher<_RenderInkFeatures>());
return result;
}
......@@ -147,7 +211,7 @@ class _MaterialState extends State<Material> {
onNotification: (LayoutChangedNotification notification) {
_inkFeatureRenderer.currentContext.findRenderObject().markNeedsPaint();
},
child: new InkFeatures(
child: new _InkFeatures(
key: _inkFeatureRenderer,
color: backgroundColor,
child: contents
......@@ -192,8 +256,8 @@ const double _kDefaultSplashRadius = 35.0; // logical pixels
const double _kSplashConfirmedVelocity = 1.0; // logical pixels per millisecond
const double _kSplashInitialSize = 0.0; // logical pixels
class RenderInkFeatures extends RenderProxyBox implements MaterialInkController {
RenderInkFeatures({ RenderBox child, this.color }) : super(child);
class _RenderInkFeatures extends RenderProxyBox implements MaterialInkController {
_RenderInkFeatures({ RenderBox child, this.color }) : super(child);
// This is here to satisfy the MaterialInkController contract.
// The actual painting of this color is done by a Container in the
......@@ -289,33 +353,44 @@ class RenderInkFeatures extends RenderProxyBox implements MaterialInkController
}
}
class InkFeatures extends SingleChildRenderObjectWidget {
InkFeatures({ Key key, this.color, Widget child }) : super(key: key, child: child);
class _InkFeatures extends SingleChildRenderObjectWidget {
_InkFeatures({ Key key, this.color, Widget child }) : super(key: key, child: child);
final Color color;
@override
RenderInkFeatures createRenderObject(BuildContext context) => new RenderInkFeatures(color: color);
_RenderInkFeatures createRenderObject(BuildContext context) => new _RenderInkFeatures(color: color);
@override
void updateRenderObject(BuildContext context, RenderInkFeatures renderObject) {
void updateRenderObject(BuildContext context, _RenderInkFeatures renderObject) {
renderObject.color = color;
}
}
/// A visual reaction on a piece of [Material].
///
/// Typically used with [MaterialInkController].
abstract class InkFeature {
/// To add an ink feature to a piece of Material, obtain the
/// [MaterialInkController] via [Material.of] and call
/// [MaterialInkController.addInkFeature].
InkFeature({
this.renderer,
this.referenceBox,
this.onRemoved
});
final RenderInkFeatures renderer;
final _RenderInkFeatures renderer;
/// The render box whose visual position defines the frame of reference for this ink feature.
final RenderBox referenceBox;
/// Called when the ink feature is no longer visible on the material.
final VoidCallback onRemoved;
bool _debugDisposed = false;
/// Free up the resources associated with this ink feature.
void dispose() {
assert(!_debugDisposed);
assert(() { _debugDisposed = true; return true; });
......@@ -343,6 +418,10 @@ abstract class InkFeature {
paintFeature(canvas, transform);
}
/// Override this method to paint the ink feature.
///
/// The transform argument gives the coordinate conversion from the coordinate
/// system of the canvas to the coodinate system of the [referenceBox].
void paintFeature(Canvas canvas, Matrix4 transform);
@override
......@@ -351,7 +430,7 @@ abstract class InkFeature {
class _InkSplash extends InkFeature implements InkSplash {
_InkSplash({
RenderInkFeatures renderer,
_RenderInkFeatures renderer,
RenderBox referenceBox,
this.position,
this.color,
......@@ -445,7 +524,7 @@ class _InkSplash extends InkFeature implements InkSplash {
class _InkHighlight extends InkFeature implements InkHighlight {
_InkHighlight({
RenderInkFeatures renderer,
_RenderInkFeatures renderer,
RenderBox referenceBox,
Color color,
this.shape,
......
......@@ -209,4 +209,4 @@ class _OverscrollIndicatorState extends State<OverscrollIndicator> {
)
);
}
}
\ No newline at end of file
}
......@@ -161,21 +161,30 @@ class TwoLevelList extends StatelessWidget {
TwoLevelList({
Key key,
this.scrollableKey,
this.items,
this.children,
this.type: MaterialListType.twoLine,
this.scrollablePadding
this.padding
}) : super(key: key);
final List<Widget> items;
/// The widgets to display in this list.
///
/// Typically [TwoLevelListItem] or [TwoLevelSublist] widgets.
final List<Widget> children;
/// The kind of [ListItem] contained in this list.
final MaterialListType type;
/// The key to use for the underlying scrollable widget.
final Key scrollableKey;
final EdgeInsets scrollablePadding;
/// The amount of space by which to inset the children inside the viewport.
final EdgeInsets padding;
@override
Widget build(BuildContext context) {
return new Block(
padding: scrollablePadding,
children: KeyedSubtree.ensureUniqueKeysForList(items),
padding: padding,
children: KeyedSubtree.ensureUniqueKeysForList(children),
scrollableKey: scrollableKey
);
}
......
......@@ -135,7 +135,9 @@ class LazyBlock extends Scrollable {
Key key,
double initialScrollOffset,
Axis scrollDirection: Axis.vertical,
ScrollListener onScrollStart,
ScrollListener onScroll,
ScrollListener onScrollEnd,
SnapOffsetCallback snapOffsetCallback,
this.delegate,
this.padding
......@@ -143,7 +145,9 @@ class LazyBlock extends Scrollable {
key: key,
initialScrollOffset: initialScrollOffset,
scrollDirection: scrollDirection,
onScrollStart: onScrollStart,
onScroll: onScroll,
onScrollEnd: onScrollEnd,
snapOffsetCallback: snapOffsetCallback
);
......
......@@ -733,7 +733,9 @@ class Block extends StatelessWidget {
this.initialScrollOffset,
this.scrollDirection: Axis.vertical,
this.scrollAnchor: ViewportAnchor.start,
this.onScrollStart,
this.onScroll,
this.onScrollEnd,
this.scrollableKey
}) : super(key: key) {
assert(children != null);
......@@ -745,10 +747,22 @@ class Block extends StatelessWidget {
/// The amount of space by which to inset the children inside the viewport.
final EdgeInsets padding;
/// The scroll offset this widget should use when first created.
final double initialScrollOffset;
final Axis scrollDirection;
final ViewportAnchor scrollAnchor;
/// Called whenever this widget starts to scroll.
final ScrollListener onScrollStart;
/// Called whenever this widget's scroll offset changes.
final ScrollListener onScroll;
/// Called whenever this widget stops scrolling.
final ScrollListener onScrollEnd;
/// The key to use for the underlying scrollable widget.
final Key scrollableKey;
@override
......@@ -761,7 +775,9 @@ class Block extends StatelessWidget {
initialScrollOffset: initialScrollOffset,
scrollDirection: scrollDirection,
scrollAnchor: scrollAnchor,
onScrollStart: onScrollStart,
onScroll: onScroll,
onScrollEnd: onScrollEnd,
child: contents
);
}
......
......@@ -19,7 +19,9 @@ class ScrollableGrid extends Scrollable {
ScrollableGrid({
Key key,
double initialScrollOffset,
ScrollListener onScrollStart,
ScrollListener onScroll,
ScrollListener onScrollEnd,
SnapOffsetCallback snapOffsetCallback,
this.delegate,
this.children
......@@ -30,7 +32,9 @@ class ScrollableGrid extends Scrollable {
// grids. For horizontally scrolling grids, we'll probably need to use a
// delegate that places children in column-major order.
scrollDirection: Axis.vertical,
onScrollStart: onScrollStart,
onScroll: onScroll,
onScrollEnd: onScrollEnd,
snapOffsetCallback: snapOffsetCallback
);
......
......@@ -51,7 +51,9 @@ class ScrollableList extends Scrollable {
double initialScrollOffset,
Axis scrollDirection: Axis.vertical,
ViewportAnchor scrollAnchor: ViewportAnchor.start,
ScrollListener onScrollStart,
ScrollListener onScroll,
ScrollListener onScrollEnd,
SnapOffsetCallback snapOffsetCallback,
this.itemExtent,
this.itemsWrap: false,
......@@ -62,7 +64,9 @@ class ScrollableList extends Scrollable {
initialScrollOffset: initialScrollOffset,
scrollDirection: scrollDirection,
scrollAnchor: scrollAnchor,
onScrollStart: onScrollStart,
onScroll: onScroll,
onScrollEnd: onScrollEnd,
snapOffsetCallback: snapOffsetCallback
) {
assert(itemExtent != null);
......
......@@ -18,7 +18,7 @@ void main() {
return new Material(
child: new Viewport(
child: new TwoLevelList(
items: <Widget>[
children: <Widget>[
new TwoLevelListItem(title: new Text('Top'), key: topKey),
new TwoLevelSublist(
key: sublistKey,
......
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