More docs about keys. (#10282)
I added a bunch of sample code to the core Widget subclasses so that people would see that you are supposed to always include the `key` argument.
This commit is contained in:
parent
f1816d6d23
commit
d4828986a6
@ -27,6 +27,8 @@ export 'package:flutter/rendering.dart' show RenderObject, RenderBox, debugDumpR
|
|||||||
/// Keys must be unique amongst the [Element]s with the same parent.
|
/// Keys must be unique amongst the [Element]s with the same parent.
|
||||||
///
|
///
|
||||||
/// Subclasses of [Key] should either subclass [LocalKey] or [GlobalKey].
|
/// Subclasses of [Key] should either subclass [LocalKey] or [GlobalKey].
|
||||||
|
///
|
||||||
|
/// See also the discussion at [Widget.key].
|
||||||
@immutable
|
@immutable
|
||||||
abstract class Key {
|
abstract class Key {
|
||||||
/// Construct a [ValueKey<String>] with the given [String].
|
/// Construct a [ValueKey<String>] with the given [String].
|
||||||
@ -45,6 +47,8 @@ abstract class Key {
|
|||||||
///
|
///
|
||||||
/// Keys must be unique amongst the [Element]s with the same parent. By
|
/// Keys must be unique amongst the [Element]s with the same parent. By
|
||||||
/// contrast, [GlobalKey]s must be unique across the entire app.
|
/// contrast, [GlobalKey]s must be unique across the entire app.
|
||||||
|
///
|
||||||
|
/// See also the discussion at [Widget.key].
|
||||||
abstract class LocalKey extends Key {
|
abstract class LocalKey extends Key {
|
||||||
/// Default constructor, used by subclasses.
|
/// Default constructor, used by subclasses.
|
||||||
const LocalKey() : super._();
|
const LocalKey() : super._();
|
||||||
@ -60,6 +64,8 @@ abstract class LocalKey extends Key {
|
|||||||
/// private, this results in a value key type that cannot collide with keys from
|
/// private, this results in a value key type that cannot collide with keys from
|
||||||
/// other sources, which could be useful, for example, if the keys are being
|
/// other sources, which could be useful, for example, if the keys are being
|
||||||
/// used as fallbacks in the same scope as keys supplied from another widget.
|
/// used as fallbacks in the same scope as keys supplied from another widget.
|
||||||
|
///
|
||||||
|
/// See also the discussion at [Widget.key].
|
||||||
class ValueKey<T> extends LocalKey {
|
class ValueKey<T> extends LocalKey {
|
||||||
/// Creates a key that delgates its [operator==] to the given value.
|
/// Creates a key that delgates its [operator==] to the given value.
|
||||||
const ValueKey(this.value);
|
const ValueKey(this.value);
|
||||||
@ -104,6 +110,8 @@ class UniqueKey extends LocalKey {
|
|||||||
///
|
///
|
||||||
/// Used to tie the identity of a widget to the identity of an object used to
|
/// Used to tie the identity of a widget to the identity of an object used to
|
||||||
/// generate that widget.
|
/// generate that widget.
|
||||||
|
///
|
||||||
|
/// See also the discussions at [Key] and [Widget.key].
|
||||||
class ObjectKey extends LocalKey {
|
class ObjectKey extends LocalKey {
|
||||||
/// Creates a key that uses [identical] on [value] for its [operator==].
|
/// Creates a key that uses [identical] on [value] for its [operator==].
|
||||||
const ObjectKey(this.value);
|
const ObjectKey(this.value);
|
||||||
@ -148,6 +156,8 @@ class ObjectKey extends LocalKey {
|
|||||||
///
|
///
|
||||||
/// You cannot simultaneously include two widgets in the tree with the same
|
/// You cannot simultaneously include two widgets in the tree with the same
|
||||||
/// global key. Attempting to do so will assert at runtime.
|
/// global key. Attempting to do so will assert at runtime.
|
||||||
|
///
|
||||||
|
/// See also the discussion at [Widget.key].
|
||||||
@optionalTypeArgs
|
@optionalTypeArgs
|
||||||
abstract class GlobalKey<T extends State<StatefulWidget>> extends Key {
|
abstract class GlobalKey<T extends State<StatefulWidget>> extends Key {
|
||||||
/// Creates a [LabeledGlobalKey], which is a [GlobalKey] with a label used for
|
/// Creates a [LabeledGlobalKey], which is a [GlobalKey] with a label used for
|
||||||
@ -406,12 +416,17 @@ abstract class Widget {
|
|||||||
/// widget is inflated into an element, and the new element is inserted into the
|
/// widget is inflated into an element, and the new element is inserted into the
|
||||||
/// tree.
|
/// tree.
|
||||||
///
|
///
|
||||||
/// Using a [GlobalKey] as the widget's [key] allows the element to be moved
|
/// In addition, using a [GlobalKey] as the widget's [key] allows the element
|
||||||
/// around the tree (changing parent) without losing state. When a new widget
|
/// to be moved around the tree (changing parent) without losing state. When a
|
||||||
/// is found (its key and type do not match a previous widget in the same
|
/// new widget is found (its key and type do not match a previous widget in
|
||||||
/// location), but there was a widget with that same global key elsewhere in
|
/// the same location), but there was a widget with that same global key
|
||||||
/// the tree in the previous frame, then that widget's element is moved to the
|
/// elsewhere in the tree in the previous frame, then that widget's element is
|
||||||
/// new location.
|
/// moved to the new location.
|
||||||
|
///
|
||||||
|
/// Generally, a widget that is the only child of another widget does not need
|
||||||
|
/// an explicit key.
|
||||||
|
///
|
||||||
|
/// See also the discussions at [Key] and [GlobalKey].
|
||||||
final Key key;
|
final Key key;
|
||||||
|
|
||||||
/// Inflates this configuration to a concrete instance.
|
/// Inflates this configuration to a concrete instance.
|
||||||
@ -483,6 +498,49 @@ abstract class Widget {
|
|||||||
/// having an internal clock-driven state, or depending on some system state,
|
/// having an internal clock-driven state, or depending on some system state,
|
||||||
/// consider using [StatefulWidget].
|
/// consider using [StatefulWidget].
|
||||||
///
|
///
|
||||||
|
/// ## Sample code
|
||||||
|
///
|
||||||
|
/// The following is a skeleton of a stateless widget subclass called `GreenFrog`:
|
||||||
|
///
|
||||||
|
/// ```dart
|
||||||
|
/// class GreenFrog extends StatelessWidget {
|
||||||
|
/// const GreenFrog({ Key key }) : super(key: key);
|
||||||
|
///
|
||||||
|
/// @override
|
||||||
|
/// Widget build(BuildContext context) {
|
||||||
|
/// return new Container(color: const Color(0xFF2DBD3A));
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Normally widgets have more constructor arguments, each of which corresponds
|
||||||
|
/// to a `final` property. The next example shows the more generic widget `Frog`
|
||||||
|
/// which can be given a color and a child:
|
||||||
|
///
|
||||||
|
/// ```dart
|
||||||
|
/// class Frog extends StatelessWidget {
|
||||||
|
/// const Frog({
|
||||||
|
/// Key key,
|
||||||
|
/// this.color: const Color(0xFF2DBD3A),
|
||||||
|
/// this.child,
|
||||||
|
/// }) : super(key: key);
|
||||||
|
///
|
||||||
|
/// final Color color;
|
||||||
|
///
|
||||||
|
/// final Widget child;
|
||||||
|
///
|
||||||
|
/// @override
|
||||||
|
/// Widget build(BuildContext context) {
|
||||||
|
/// return new Container(color: color, child: child);
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// By convention, widget constructors only use named arguments. Named arguments
|
||||||
|
/// can be marked as required using [@required]. Also by convention, the first
|
||||||
|
/// argument is [key], and the last argument is `child`, `children`, or the
|
||||||
|
/// equivalent.
|
||||||
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [StatefulWidget] and [State], for widgets that can build differently
|
/// * [StatefulWidget] and [State], for widgets that can build differently
|
||||||
@ -583,6 +641,72 @@ abstract class StatelessWidget extends Widget {
|
|||||||
/// eligible for grafting, the widget might be inserted into the new location in
|
/// eligible for grafting, the widget might be inserted into the new location in
|
||||||
/// the same animation frame in which it was removed from the old location.
|
/// the same animation frame in which it was removed from the old location.
|
||||||
///
|
///
|
||||||
|
/// ## Sample code
|
||||||
|
///
|
||||||
|
/// The following is a skeleton of a stateful widget subclass called `GreenFrog`:
|
||||||
|
///
|
||||||
|
/// ```dart
|
||||||
|
/// class GreenFrog extends StatefulWidget {
|
||||||
|
/// const GreenFrog({ Key key }) : super(key: key);
|
||||||
|
///
|
||||||
|
/// @override
|
||||||
|
/// _GreenFrogState createState() => new _GreenFrogState();
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// class _GreenFrogState extends State<GreenFrog> {
|
||||||
|
/// @override
|
||||||
|
/// Widget build(BuildContext context) {
|
||||||
|
/// return new Container(color: const Color(0xFF2DBD3A));
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// In this example. the [State] has no actual state. State is normally
|
||||||
|
/// represented as private member fields. Also, normally widgets have more
|
||||||
|
/// constructor arguments, each of which corresponds to a `final` property.
|
||||||
|
///
|
||||||
|
/// The next example shows the more generic widget `Frog` which can be given a
|
||||||
|
/// color and a child, and which has some internal state with a method that
|
||||||
|
/// can be called to mutate it:
|
||||||
|
///
|
||||||
|
/// ```dart
|
||||||
|
/// class Frog extends StatelessWidget {
|
||||||
|
/// const Frog({
|
||||||
|
/// Key key,
|
||||||
|
/// this.color: const Color(0xFF2DBD3A),
|
||||||
|
/// this.child,
|
||||||
|
/// }) : super(key: key);
|
||||||
|
///
|
||||||
|
/// final Color color;
|
||||||
|
///
|
||||||
|
/// final Widget child;
|
||||||
|
///
|
||||||
|
/// _FrogState createState() => new _FrogState();
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// class _FrogState extends State<Frog> {
|
||||||
|
/// double _size = 1.0;
|
||||||
|
///
|
||||||
|
/// void grow() {
|
||||||
|
/// setState(() { _size += 0.1; });
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// @override
|
||||||
|
/// Widget build(BuildContext context) {
|
||||||
|
/// return new Container(
|
||||||
|
/// color: widget.color,
|
||||||
|
/// transform: new Matrix4.diagonalValues(_size, _size, 1.0),
|
||||||
|
/// child: widget.child,
|
||||||
|
/// );
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// By convention, widget constructors only use named arguments. Named arguments
|
||||||
|
/// can be marked as required using [@required]. Also by convention, the first
|
||||||
|
/// argument is [key], and the last argument is `child`, `children`, or the
|
||||||
|
/// equivalent.
|
||||||
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [State], where the logic behind a [StatefulWidget] is hosted.
|
/// * [State], where the logic behind a [StatefulWidget] is hosted.
|
||||||
@ -721,12 +845,13 @@ typedef void StateSetter(VoidCallback fn);
|
|||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [StatefulWidget], where the current configuration of a [State] is hosted
|
/// * [StatefulWidget], where the current configuration of a [State] is hosted,
|
||||||
/// (see [Widget]).
|
/// and whose documentation has sample code for [State].
|
||||||
/// * [StatelessWidget], for widgets that always build the same way given a
|
/// * [StatelessWidget], for widgets that always build the same way given a
|
||||||
/// particular configuration and ambient state.
|
/// particular configuration and ambient state.
|
||||||
/// * [InheritedWidget], for widgets that introduce ambient state that can
|
/// * [InheritedWidget], for widgets that introduce ambient state that can
|
||||||
/// be read by descendant widgets.
|
/// be read by descendant widgets.
|
||||||
|
/// * [Widget], for an overview of widgets in general.
|
||||||
@optionalTypeArgs
|
@optionalTypeArgs
|
||||||
abstract class State<T extends StatefulWidget> {
|
abstract class State<T extends StatefulWidget> {
|
||||||
/// The current configuration.
|
/// The current configuration.
|
||||||
@ -1140,10 +1265,24 @@ abstract class State<T extends StatefulWidget> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A widget that has exactly one child widget.
|
/// A widget that has a child widget provided to it, instead of building a new
|
||||||
|
/// widget.
|
||||||
///
|
///
|
||||||
/// Useful as a base class for other widgets, such as [InheritedWidget] and
|
/// Useful as a base class for other widgets, such as [InheritedWidget] and
|
||||||
/// [ParentDataWidget].
|
/// [ParentDataWidget].
|
||||||
|
///
|
||||||
|
/// See also:
|
||||||
|
///
|
||||||
|
/// * [InheritedWidget], for widgets that introduce ambient state that can
|
||||||
|
/// be read by descendant widgets.
|
||||||
|
/// * [ParentDataWidget], for widgets that populate the
|
||||||
|
/// [RenderObject.parentData] slot of their child's [RenderObject] to
|
||||||
|
/// configure the parent widget's layout.
|
||||||
|
/// * [StatefulWidget] and [State], for widgets that can build differently
|
||||||
|
/// several times over their lifetime.
|
||||||
|
/// * [StatelessWidget], for widgets that always build the same way given a
|
||||||
|
/// particular configuration and ambient state.
|
||||||
|
/// * [Widget], for an overview of widgets in general.
|
||||||
abstract class ProxyWidget extends Widget {
|
abstract class ProxyWidget extends Widget {
|
||||||
/// Creates a widget that has exactly one child widget.
|
/// Creates a widget that has exactly one child widget.
|
||||||
const ProxyWidget({ Key key, @required this.child }) : super(key: key);
|
const ProxyWidget({ Key key, @required this.child }) : super(key: key);
|
||||||
@ -1162,6 +1301,46 @@ abstract class ProxyWidget extends Widget {
|
|||||||
/// A [ParentDataWidget] is specific to a particular kind of [RenderObject], and
|
/// A [ParentDataWidget] is specific to a particular kind of [RenderObject], and
|
||||||
/// thus also to a particular [RenderObjectWidget] class. That class is `T`, the
|
/// thus also to a particular [RenderObjectWidget] class. That class is `T`, the
|
||||||
/// [ParentDataWidget] type argument.
|
/// [ParentDataWidget] type argument.
|
||||||
|
///
|
||||||
|
/// ## Sample code
|
||||||
|
///
|
||||||
|
/// This example shows how you would build a [ParentDataWidget] to configure a
|
||||||
|
/// `FrogJar` widget's children by specifying a [Size] for each one.
|
||||||
|
///
|
||||||
|
/// ```dart
|
||||||
|
/// class FrogSize extends ParentDataWidget<FrogJar> {
|
||||||
|
/// Pond({
|
||||||
|
/// Key key,
|
||||||
|
/// @required this.size,
|
||||||
|
/// @required Widget child,
|
||||||
|
/// }) : assert(child != null),
|
||||||
|
/// assert(size != null),
|
||||||
|
/// super(key: key, child: child);
|
||||||
|
///
|
||||||
|
/// final Size size;
|
||||||
|
///
|
||||||
|
/// @override
|
||||||
|
/// void applyParentData(RenderObject renderObject) {
|
||||||
|
/// final FrogJarParentData parentData = renderObject.parentData;
|
||||||
|
/// if (parentData.size != size) {
|
||||||
|
/// parentData.size = size;
|
||||||
|
/// final RenderFrogJar targetParent = renderObject.parent;
|
||||||
|
/// targetParent.markNeedsLayout();
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// See also:
|
||||||
|
///
|
||||||
|
/// * [RenderObject], the superclass for layout algorithms.
|
||||||
|
/// * [RenderObject.parentData], the slot that this class configures.
|
||||||
|
/// * [ParentData], the superclass of the data that will be placed in
|
||||||
|
/// [RenderObject.parentData] slots.
|
||||||
|
/// * [RenderObjectWidget], the class for widgets that wrap [RenderObject]s.
|
||||||
|
/// The `T` type parameter for [ParentDataWidget] is a [RenderObjectWidget].
|
||||||
|
/// * [StatefulWidget] and [State], for widgets that can build differently
|
||||||
|
/// several times over their lifetime.
|
||||||
abstract class ParentDataWidget<T extends RenderObjectWidget> extends ProxyWidget {
|
abstract class ParentDataWidget<T extends RenderObjectWidget> extends ProxyWidget {
|
||||||
/// Abstract const constructor. This constructor enables subclasses to provide
|
/// Abstract const constructor. This constructor enables subclasses to provide
|
||||||
/// const constructors so that they can be used in const expressions.
|
/// const constructors so that they can be used in const expressions.
|
||||||
@ -1239,6 +1418,56 @@ abstract class ParentDataWidget<T extends RenderObjectWidget> extends ProxyWidge
|
|||||||
///
|
///
|
||||||
/// Inherited widgets, when referenced in this way, will cause the consumer to
|
/// Inherited widgets, when referenced in this way, will cause the consumer to
|
||||||
/// rebuild when the inherited widget itself changes state.
|
/// rebuild when the inherited widget itself changes state.
|
||||||
|
///
|
||||||
|
/// ## Sample code
|
||||||
|
///
|
||||||
|
/// The following is a skeleton of an inherited widget called `FrogColor`:
|
||||||
|
///
|
||||||
|
/// ```dart
|
||||||
|
/// class FrogColor extends InheritedWidget {
|
||||||
|
/// const FrogColor(
|
||||||
|
/// Key key,
|
||||||
|
/// @required this.color,
|
||||||
|
/// @required Widget child,
|
||||||
|
/// }) : assert(color != null),
|
||||||
|
/// assert(child != null),
|
||||||
|
/// super(key: key, child: child);
|
||||||
|
///
|
||||||
|
/// final Color color;
|
||||||
|
///
|
||||||
|
/// static FrogColor of(BuildContext context) {
|
||||||
|
/// return context.inheritFromWidgetOfExactType(FrogColor);
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// @override
|
||||||
|
/// bool updateShouldNotify(FrogColor old) => color != old.color;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// The convention is to provide a static method `of` on the [InheritedWidget]
|
||||||
|
/// which does the call to [BuildContext.inheritFromWidgetOfExactType]. This
|
||||||
|
/// allows the class to define its own fallback logic in the case of there not
|
||||||
|
/// being a widget in scope. In the example above, the value returned will be
|
||||||
|
/// null in that case, but it could also have defaulted to a value.
|
||||||
|
///
|
||||||
|
/// Sometimes, the `of` method returns the data rather than the inherited
|
||||||
|
/// widget; for example, in this case it could have returned a [Color] instead
|
||||||
|
/// of the [FrogColor] widget.
|
||||||
|
///
|
||||||
|
/// Occasionally, the inherited widget is an implementation detail of another
|
||||||
|
/// class, and is therefore private. The `of` method in that case is typically
|
||||||
|
/// put on the public class instead. For example, [Theme] is implemented as a
|
||||||
|
/// [StatelessWidget] that builds a private inherited widget; [Theme.of] looks
|
||||||
|
/// for that inherited widget using [BuildContext.inheritFromWidgetOfExactType]
|
||||||
|
/// and then returns the [ThemeData].
|
||||||
|
///
|
||||||
|
/// See also:
|
||||||
|
///
|
||||||
|
/// * [StatefulWidget] and [State], for widgets that can build differently
|
||||||
|
/// several times over their lifetime.
|
||||||
|
/// * [StatelessWidget], for widgets that always build the same way given a
|
||||||
|
/// particular configuration and ambient state.
|
||||||
|
/// * [Widget], for an overview of widgets in general.
|
||||||
abstract class InheritedWidget extends ProxyWidget {
|
abstract class InheritedWidget extends ProxyWidget {
|
||||||
/// Abstract const constructor. This constructor enables subclasses to provide
|
/// Abstract const constructor. This constructor enables subclasses to provide
|
||||||
/// const constructors so that they can be used in const expressions.
|
/// const constructors so that they can be used in const expressions.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user