Commit 50610766 authored by Ian Hickson's avatar Ian Hickson

Try to clarify that you need a Material for an IconButton.

Fixes https://github.com/flutter/flutter/issues/2369
parent d55e5a69
...@@ -80,7 +80,7 @@ class _BottomSheetState extends State<BottomSheet> { ...@@ -80,7 +80,7 @@ class _BottomSheetState extends State<BottomSheet> {
onVerticalDragUpdate: _handleDragUpdate, onVerticalDragUpdate: _handleDragUpdate,
onVerticalDragEnd: _handleDragEnd, onVerticalDragEnd: _handleDragEnd,
child: new Material( child: new Material(
key: _childKey, key: _childKey,
child: config.builder(context) child: config.builder(context)
) )
); );
......
...@@ -10,6 +10,7 @@ import 'package:intl/date_symbols.dart'; ...@@ -10,6 +10,7 @@ import 'package:intl/date_symbols.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'colors.dart'; import 'colors.dart';
import 'debug.dart';
import 'ink_well.dart'; import 'ink_well.dart';
import 'theme.dart'; import 'theme.dart';
import 'typography.dart'; import 'typography.dart';
...@@ -403,6 +404,7 @@ class _YearPickerState extends State<YearPicker> { ...@@ -403,6 +404,7 @@ class _YearPickerState extends State<YearPicker> {
} }
Widget build(BuildContext context) { Widget build(BuildContext context) {
assert(debugCheckHasMaterial(context));
return new ScrollableLazyList( return new ScrollableLazyList(
itemExtent: _itemExtent, itemExtent: _itemExtent,
itemCount: config.lastDate.year - config.firstDate.year + 1, itemCount: config.lastDate.year - config.firstDate.year + 1,
......
...@@ -12,8 +12,15 @@ bool debugCheckHasMaterial(BuildContext context) { ...@@ -12,8 +12,15 @@ bool debugCheckHasMaterial(BuildContext context) {
if (context.widget is! Material && context.ancestorWidgetOfExactType(Material) == null) { if (context.widget is! Material && context.ancestorWidgetOfExactType(Material) == null) {
Element element = context; Element element = context;
throw new WidgetError( throw new WidgetError(
'Missing Material widget.', 'No Material widget found.\n'
'${context.widget} needs to be placed inside a Material widget. Ownership chain:\n${element.debugGetOwnershipChain(10)}' '${context.widget} widgets require a Material widget ancestor.\n'
'In material design, most widgets are conceptually "printed" on a sheet of material. In Flutter\'s material library, '
'that material is represented by the Material widget. It is the Material widget that renders ink splashes, for instance. '
'Because of this, many material library widgets require that there be a Material widget in the tree above them.\n'
'To introduce a Material widget, you can either directly include one, or use a widget that contains Material itself, '
'such as a Card, Dialog, Drawer, or Scaffold.\n'
'The ownership chain for the affected widget is:\n'
' ${element.debugGetOwnershipChain(10)}'
); );
} }
return true; return true;
...@@ -27,8 +34,10 @@ bool debugCheckHasScaffold(BuildContext context) { ...@@ -27,8 +34,10 @@ bool debugCheckHasScaffold(BuildContext context) {
if (Scaffold.of(context) == null) { if (Scaffold.of(context) == null) {
Element element = context; Element element = context;
throw new WidgetError( throw new WidgetError(
'Missing Scaffold widget.', 'No Scaffold widget found.\n'
'${context.widget} needs to be placed inside the body of a Scaffold widget. Ownership chain:\n${element.debugGetOwnershipChain(10)}' '${context.widget} widgets require a Scaffold widget ancestor.\n'
'The ownership chain for the affected widget is:\n'
' ${element.debugGetOwnershipChain(10)}'
); );
} }
return true; return true;
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'colors.dart'; import 'colors.dart';
import 'debug.dart';
import 'icon.dart'; import 'icon.dart';
import 'icons.dart'; import 'icons.dart';
import 'ink_well.dart'; import 'ink_well.dart';
...@@ -55,6 +56,7 @@ class DrawerItem extends StatelessComponent { ...@@ -55,6 +56,7 @@ class DrawerItem extends StatelessComponent {
} }
Widget build(BuildContext context) { Widget build(BuildContext context) {
assert(debugCheckHasMaterial(context));
ThemeData themeData = Theme.of(context); ThemeData themeData = Theme.of(context);
List<Widget> children = <Widget>[]; List<Widget> children = <Widget>[];
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'debug.dart';
import 'icon.dart'; import 'icon.dart';
import 'icons.dart'; import 'icons.dart';
import 'ink_well.dart'; import 'ink_well.dart';
...@@ -53,6 +54,7 @@ class IconButton extends StatelessComponent { ...@@ -53,6 +54,7 @@ class IconButton extends StatelessComponent {
final String tooltip; final String tooltip;
Widget build(BuildContext context) { Widget build(BuildContext context) {
assert(debugCheckHasMaterial(context));
Widget result = new Padding( Widget result = new Padding(
padding: const EdgeDims.all(8.0), padding: const EdgeDims.all(8.0),
child: new Icon( child: new Icon(
......
...@@ -12,6 +12,18 @@ import 'debug.dart'; ...@@ -12,6 +12,18 @@ import 'debug.dart';
import 'material.dart'; import 'material.dart';
import 'theme.dart'; import 'theme.dart';
/// An area of a Material that responds to touch. Has a configurable shape and
/// can be configured to clip splashes that extend outside its bounds or not.
///
/// For a variant of this widget that is specialised for rectangular areas that
/// always clip splashes, see [InkWell].
///
/// Must have an ancestor [Material] widget in which to cause ink reactions.
///
/// If a Widget uses this class directly, it should include the following line
/// at the top of its [build] function to call [debugCheckHasMaterial]:
///
/// assert(debugCheckHasMaterial(context));
class InkResponse extends StatefulComponent { class InkResponse extends StatefulComponent {
InkResponse({ InkResponse({
Key key, Key key,
...@@ -156,9 +168,14 @@ class _InkResponseState<T extends InkResponse> extends State<T> { ...@@ -156,9 +168,14 @@ class _InkResponseState<T extends InkResponse> extends State<T> {
} }
/// An area of a Material that responds to touch. /// A rectangular area of a Material that responds to touch.
///
/// Must have an ancestor [Material] widget in which to cause ink reactions.
///
/// If a Widget uses this class directly, it should include the following line
/// at the top of its [build] function to call [debugCheckHasMaterial]:
/// ///
/// Must have an ancestor Material widget in which to cause ink reactions. /// assert(debugCheckHasMaterial(context));
class InkWell extends InkResponse { class InkWell extends InkResponse {
InkWell({ InkWell({
Key key, Key key,
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'debug.dart';
import 'ink_well.dart'; import 'ink_well.dart';
import 'theme.dart'; import 'theme.dart';
...@@ -85,6 +86,7 @@ class ListItem extends StatelessComponent { ...@@ -85,6 +86,7 @@ class ListItem extends StatelessComponent {
} }
Widget build(BuildContext context) { Widget build(BuildContext context) {
assert(debugCheckHasMaterial(context));
final bool isTwoLine = !isThreeLine && secondary != null; final bool isTwoLine = !isThreeLine && secondary != null;
final bool isOneLine = !isThreeLine && !isTwoLine; final bool isOneLine = !isThreeLine && !isTwoLine;
double itemHeight; double itemHeight;
......
...@@ -10,6 +10,7 @@ import 'package:flutter/rendering.dart'; ...@@ -10,6 +10,7 @@ import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'colors.dart'; import 'colors.dart';
import 'debug.dart';
import 'icon.dart'; import 'icon.dart';
import 'icons.dart'; import 'icons.dart';
import 'icon_theme.dart'; import 'icon_theme.dart';
...@@ -330,6 +331,7 @@ class _Tab extends StatelessComponent { ...@@ -330,6 +331,7 @@ class _Tab extends StatelessComponent {
} }
Widget build(BuildContext context) { Widget build(BuildContext context) {
assert(debugCheckHasMaterial(context));
Widget labelContent; Widget labelContent;
if (label.icon == null && label.iconBuilder == null) { if (label.icon == null && label.iconBuilder == null) {
labelContent = _buildLabelText(); labelContent = _buildLabelText();
......
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