Doc and Error Message Improvements (#60726)

This commit is contained in:
Kate Lovett 2020-07-07 17:49:03 -07:00 committed by GitHub
parent e8e1eb51a4
commit 3176232cb4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 142 additions and 40 deletions

View file

@ -23,6 +23,11 @@ const EdgeInsets _kBackgroundButtonPadding = EdgeInsets.symmetric(
/// Takes in a text or an icon that fades out and in on touch. May optionally have a
/// background.
///
/// The [padding] defaults to 16.0 pixels. When using a [CupertinoButton] within
/// a fixed height parent, like a [CupertinoNavigationBar], a smaller, or even
/// [EdgeInsets.zero], should be used to prevent clipping larger [child]
/// widgets.
///
/// See also:
///
/// * <https://developer.apple.com/ios/human-interface-guidelines/controls/buttons/>

View file

@ -674,7 +674,8 @@ class ListTile extends StatelessWidget {
///
/// Typically a [Text] widget.
///
/// This should not wrap.
/// This should not wrap. To enforce the single line limit, use
/// [Text.maxLines].
final Widget title;
/// Additional content displayed below the title.
@ -684,7 +685,8 @@ class ListTile extends StatelessWidget {
/// If [isThreeLine] is false, this should not wrap.
///
/// If [isThreeLine] is true, this should be configured to take a maximum of
/// two lines.
/// two lines. For example, you can use [Text.maxLines] to enforce the number
/// of lines.
final Widget subtitle;
/// A widget to display after the title.
@ -705,6 +707,9 @@ class ListTile extends StatelessWidget {
///
/// If false, the list tile is treated as having one line if the subtitle is
/// null and treated as having two lines if the subtitle is non-null.
///
/// When using a [Text] widget for [title] and [subtitle], you can enforce
/// line limits using [Text.maxLines].
final bool isThreeLine;
/// Whether this list tile is part of a vertically dense list.

View file

@ -36,6 +36,10 @@ export 'package:flutter/services.dart' show SmartQuotesType, SmartDashesType;
/// Remember to [dispose] of the [TextEditingController] when it is no longer needed.
/// This will ensure we discard any resources used by the object.
///
/// By default, [TextFormField.decoration] will apply the
/// [ThemeData.inputDecorationTheme] for the current context to the
/// [InputDecoration], see [InputDecoration.applyDefaults].
///
/// For a documentation about the various parameters, see [TextField].
///
/// {@tool snippet}

View file

@ -393,26 +393,21 @@ class Border extends BoxBorder {
}
@override
bool get isUniform {
bool get isUniform => _colorIsUniform && _widthIsUniform && _styleIsUniform;
bool get _colorIsUniform {
final Color topColor = top.color;
if (right.color != topColor ||
bottom.color != topColor ||
left.color != topColor)
return false;
return right.color == topColor && bottom.color == topColor && left.color == topColor;
}
bool get _widthIsUniform {
final double topWidth = top.width;
if (right.width != topWidth ||
bottom.width != topWidth ||
left.width != topWidth)
return false;
return right.width == topWidth && bottom.width == topWidth && left.width == topWidth;
}
bool get _styleIsUniform {
final BorderStyle topStyle = top.style;
if (right.style != topStyle ||
bottom.style != topStyle ||
left.style != topStyle)
return false;
return true;
return right.style == topStyle && bottom.style == topStyle && left.style == topStyle;
}
@override
@ -522,8 +517,30 @@ class Border extends BoxBorder {
}
}
assert(borderRadius == null, 'A borderRadius can only be given for uniform borders.');
assert(shape == BoxShape.rectangle, 'A border can only be drawn as a circle if it is uniform.');
assert(() {
if (borderRadius != null) {
throw FlutterError.fromParts(<DiagnosticsNode>[
ErrorSummary('A borderRadius can only be given for a uniform Border.'),
ErrorDescription('The following is not uniform:'),
if (!_colorIsUniform) ErrorDescription('BorderSide.color'),
if (!_widthIsUniform) ErrorDescription('BorderSide.width'),
if (!_styleIsUniform) ErrorDescription('BorderSide.style'),
]);
}
return true;
}());
assert(() {
if (shape != BoxShape.rectangle) {
throw FlutterError.fromParts(<DiagnosticsNode>[
ErrorSummary('A Border can only be drawn as a circle if it is uniform'),
ErrorDescription('The following is not uniform:'),
if (!_colorIsUniform) ErrorDescription('BorderSide.color'),
if (!_widthIsUniform) ErrorDescription('BorderSide.width'),
if (!_styleIsUniform) ErrorDescription('BorderSide.style'),
]);
}
return true;
}());
paintBorder(canvas, rect, top: top, right: right, bottom: bottom, left: left);
}

View file

@ -1705,13 +1705,16 @@ abstract class RenderBox extends RenderObject {
if (_size is _DebugSize) {
assert(_size._owner == this);
if (RenderObject.debugActiveLayout != null) {
// We are always allowed to access our own size (for print debugging
// and asserts if nothing else). Other than us, the only object that's
// allowed to read our size is our parent, if they've said they will.
// If you hit this assert trying to access a child's size, pass
// "parentUsesSize: true" to that child's layout().
assert(debugDoingThisResize || debugDoingThisLayout ||
(RenderObject.debugActiveLayout == parent && _size._canBeUsedByParent));
assert(
debugDoingThisResize || debugDoingThisLayout ||
(RenderObject.debugActiveLayout == parent && _size._canBeUsedByParent),
'RenderBox.size accessed beyond the scope of resize, layout, or '
'permitted parent access. RenderBox can always access its own size, '
'otherwise, the only object that is allowed to read RenderBox.size '
'is its parent, if they have said they will. It you hit this assert '
'trying to access a child\'s size, pass "parentUsesSize: true" to '
'that child\'s layout().'
);
}
assert(_size == this._size);
}

View file

@ -414,7 +414,8 @@ class SliverGridDelegateWithMaxCrossAxisExtent extends SliverGridDelegate {
/// The ratio of the cross-axis to the main-axis extent of each child.
final double childAspectRatio;
bool _debugAssertIsValid() {
bool _debugAssertIsValid(double crossAxisExtent) {
assert(crossAxisExtent > 0.0);
assert(maxCrossAxisExtent > 0.0);
assert(mainAxisSpacing >= 0.0);
assert(crossAxisSpacing >= 0.0);
@ -424,7 +425,7 @@ class SliverGridDelegateWithMaxCrossAxisExtent extends SliverGridDelegate {
@override
SliverGridLayout getLayout(SliverConstraints constraints) {
assert(_debugAssertIsValid());
assert(_debugAssertIsValid(constraints.crossAxisExtent));
final int crossAxisCount = (constraints.crossAxisExtent / (maxCrossAxisExtent + crossAxisSpacing)).ceil();
final double usableCrossAxisExtent = constraints.crossAxisExtent - crossAxisSpacing * (crossAxisCount - 1);
final double childCrossAxisExtent = usableCrossAxisExtent / crossAxisCount;

View file

@ -276,6 +276,8 @@ enum StackFit {
/// visible.
enum Overflow {
/// Overflowing children will be visible.
///
/// The visible overflow area will not accept hit testing.
visible,
/// Overflowing children will be clipped to the bounds of their parent.

View file

@ -13,6 +13,41 @@ import 'framework.dart';
/// Animated widget that automatically transitions its size over a given
/// duration whenever the given child's size changes.
///
/// {@tool dartpad --template=stateful_widget_scaffold_center_freeform_state}
/// This example makes a [Container] react to being touched, causing the child
/// of the [AnimatedSize] widget, here a [FlutterLogo], to animate.
///
/// ```dart
/// class _MyStatefulWidgetState extends State<MyStatefulWidget> with SingleTickerProviderStateMixin {
/// double _size = 50.0;
/// bool _large = false;
///
/// void _updateSize() {
/// setState(() {
/// _size = _large ? 250.0 : 100.0;
/// _large = !_large;
/// });
/// }
///
/// @override
/// Widget build(BuildContext context) {
/// return GestureDetector(
/// onTap: () => _updateSize(),
/// child: Container(
/// color: Colors.amberAccent,
/// child: AnimatedSize(
/// curve: Curves.easeIn,
/// vsync: this,
/// duration: Duration(seconds: 1),
/// child: FlutterLogo(size: _size),
/// ),
/// ),
/// );
/// }
/// }
/// ```
/// {@end-tool}
///
/// See also:
///
/// * [SizeTransition], which changes its size based on an [Animation].

View file

@ -3285,6 +3285,9 @@ class Stack extends MultiChildRenderObjectWidget {
/// Some children in a stack might overflow its box. When this flag is set to
/// [Overflow.clip], children cannot paint outside of the stack's box.
///
/// When set to [Overflow.visible], the visible overflow area will not accept
/// hit testing.
///
/// This overrides [clipBehavior] for now due to a staged roll out without
/// breaking Google. We will remove it and only use [clipBehavior] soon.
final Overflow overflow;

View file

@ -300,6 +300,10 @@ class _LocalizationsScope extends InheritedWidget {
/// `Localizations.of(context)` will be rebuilt after the resources
/// for the new locale have been loaded.
///
/// The `Localizations` widget also instantiates [Directionality] in order to
/// support the appropriate [Directionality.textDirection] of the localized
/// resources.
///
/// {@tool snippet}
///
/// This following class is defined in terms of the

View file

@ -2404,7 +2404,11 @@ class _RouteEntry extends RouteTransitionRecord {
assert(currentState == _RouteLifecycle.push || currentState == _RouteLifecycle.pushReplace || currentState == _RouteLifecycle.replace);
assert(navigator != null);
assert(navigator._debugLocked);
assert(route._navigator == null);
assert(
route._navigator == null,
'The pushed route has already been used. When pushing a route, a new '
'Route object must be provided.',
);
final _RouteLifecycle previousState = currentState;
route._navigator = navigator;
route.install();

View file

@ -1051,12 +1051,13 @@ class ListView extends BoxScrollView {
/// The `itemBuilder` callback will be called only with indices greater than
/// or equal to zero and less than `itemCount`.
///
/// The `itemBuilder` should actually create the widget instances when called.
/// Avoid using a builder that returns a previously-constructed widget; if the
/// list view's children are created in advance, or all at once when the
/// [ListView] itself is created, it is more efficient to use the [ListView]
/// constructor. Even more efficient, however, is to create the instances on
/// demand using this constructor's `itemBuilder` callback.
/// The `itemBuilder` should always return a non-null widget, and actually
/// create the widget instances when called. Avoid using a builder that
/// returns a previously-constructed widget; if the list view's children are
/// created in advance, or all at once when the [ListView] itself is created,
/// it is more efficient to use the [ListView] constructor. Even more
/// efficient, however, is to create the instances on demand using this
/// constructor's `itemBuilder` callback.
///
/// The `addAutomaticKeepAlives` argument corresponds to the
/// [SliverChildBuilderDelegate.addAutomaticKeepAlives] property. The
@ -1128,11 +1129,11 @@ class ListView extends BoxScrollView {
/// The `separatorBuilder` callback will be called with indices greater than
/// or equal to zero and less than `itemCount - 1`.
///
/// The `itemBuilder` and `separatorBuilder` callbacks should actually create
/// widget instances when called. Avoid using a builder that returns a
/// previously-constructed widget; if the list view's children are created in
/// advance, or all at once when the [ListView] itself is created, it is more
/// efficient to use the [ListView] constructor.
/// The `itemBuilder` and `separatorBuilder` callbacks should always return a
/// non-null widget, and actually create widget instances when called. Avoid
/// using a builder that returns a previously-constructed widget; if the list
/// view's children are created in advance, or all at once when the [ListView]
/// itself is created, it is more efficient to use the [ListView] constructor.
///
/// {@tool snippet}
///
@ -1439,6 +1440,24 @@ class ListView extends BoxScrollView {
/// extremities to avoid partial obstructions indicated by [MediaQuery]'s
/// padding. To avoid this behavior, override with a zero [padding] property.
///
/// {@tool snippet}
/// The following example demonstrates how to override the default top padding
/// using [MediaQuery.removePadding].
///
/// ```dart
/// Widget myWidget(BuildContext context) {
/// return MediaQuery.removePadding(
/// context: context,
/// removeTop: true,
/// child: ListView.builder(
/// itemCount: 25,
/// itemBuilder: (BuildContext context, int index) => ListTile(title: Text('item $index')),
/// )
/// );
/// }
/// ```
/// {@end-tool}
///
/// Once code has been ported to use [CustomScrollView], other slivers, such as
/// [SliverList] or [SliverAppBar], can be put in the [CustomScrollView.slivers]
/// list.