From a663d2550ff196c43493390ed4632b4e7ff9676f Mon Sep 17 00:00:00 2001 From: Adam Barth Date: Fri, 5 Feb 2016 10:08:12 -0800 Subject: [PATCH] Add more dartdoc to widgets.dart Making progress documenting the widget library. --- packages/flutter/lib/src/widgets/focus.dart | 31 +++++ .../flutter/lib/src/widgets/gridpaper.dart | 8 ++ .../lib/src/widgets/implicit_animations.dart | 13 +- .../flutter/lib/src/widgets/locale_query.dart | 2 + packages/flutter/lib/src/widgets/mimic.dart | 3 + .../flutter/lib/src/widgets/navigator.dart | 129 +++++++++++++++++- .../src/widgets/notification_listener.dart | 5 + .../flutter/lib/src/widgets/page_storage.dart | 13 ++ 8 files changed, 194 insertions(+), 10 deletions(-) diff --git a/packages/flutter/lib/src/widgets/focus.dart b/packages/flutter/lib/src/widgets/focus.dart index 82ab9be7e27..93b929fafd2 100644 --- a/packages/flutter/lib/src/widgets/focus.dart +++ b/packages/flutter/lib/src/widgets/focus.dart @@ -69,6 +69,28 @@ class _FocusScope extends InheritedWidget { } } +/// A scope for managing the focus state of descendant widgets. +/// +/// The focus represents where the user's attention is directed. If the use +/// interacts with the system in a way that isn't visually directed at a +/// particular widget (e.g., by typing on a keyboard), the interaction is +/// directed to the currently focused widget. +/// +/// The focus system consists of a tree of Focus widgets, which is embedded in +/// the widget tree. Focus widgets themselves can be focused in their enclosing +/// Focus widget, which means that their subtree is the one that has the current +/// focus. For example, a dialog creates a Focus widget to maintain focus +/// within the dialog. When the dialog closes, its Focus widget is removed from +/// the tree and focus is restored to whichever other part of the Focus tree +/// previously had focus. +/// +/// In addition to tracking which enclosed Focus widget has focus, each Focus +/// widget also tracks a GlobalKey, which represents the currently focused +/// widget in this part of the focus tree. If this Focus widget is the currently +/// focused subtree of the focus system (i.e., the path from it to the root is +/// focused at each level and it hasn't focused any of its enclosed Focus +/// widgets), then the widget this this global key actually has the focus in the +/// entire system. class Focus extends StatefulComponent { Focus({ GlobalKey key, @@ -79,8 +101,15 @@ class Focus extends StatefulComponent { final Widget child; + /// The key that currently has focus globally in the entire focus tree. + /// + /// This field is always null except in checked mode. static GlobalKey debugOnlyFocusedKey; + /// Whether the focus is current at the given context. + /// + /// If autofocus is true, the given context will become focused if no other + /// widget is already focused. static bool at(BuildContext context, { bool autofocus: false }) { assert(context != null); assert(context.widget != null); @@ -134,6 +163,8 @@ class Focus extends StatefulComponent { } } + /// Unfocuses the currently focused widget (if any) in the Focus that most + /// tightly encloses the given context. static void clear(BuildContext context) { _FocusScope focusScope = context.ancestorWidgetOfExactType(_FocusScope); if (focusScope != null) diff --git a/packages/flutter/lib/src/widgets/gridpaper.dart b/packages/flutter/lib/src/widgets/gridpaper.dart index 1d9872c8e66..eea8af196bf 100644 --- a/packages/flutter/lib/src/widgets/gridpaper.dart +++ b/packages/flutter/lib/src/widgets/gridpaper.dart @@ -56,10 +56,18 @@ class GridPaper extends StatelessComponent { this.child }) : super(key: key); + /// The color to draw the lines in the grid. final Color color; + + /// The distance between the primary lines in the grid, in logical pixels. final double interval; + + /// The number of major divisions within each primary grid cell. final int divisions; + + /// The number of minor divisions within each major division. final int subDivisions; + final Widget child; Widget build(BuildContext context) { diff --git a/packages/flutter/lib/src/widgets/implicit_animations.dart b/packages/flutter/lib/src/widgets/implicit_animations.dart index 9030ea7bd1e..94b705497e7 100644 --- a/packages/flutter/lib/src/widgets/implicit_animations.dart +++ b/packages/flutter/lib/src/widgets/implicit_animations.dart @@ -9,14 +9,14 @@ import 'framework.dart'; import 'package:vector_math/vector_math_64.dart'; -/// An animated value that interpolates [BoxConstraint]s. +/// An interpolation between two [BoxConstraint]s. class BoxConstraintsTween extends Tween { BoxConstraintsTween({ BoxConstraints begin, BoxConstraints end }) : super(begin: begin, end: end); BoxConstraints lerp(double t) => BoxConstraints.lerp(begin, end, t); } -/// An animated value that interpolates [Decoration]s. +/// An interpolation between two [Decoration]s. class DecorationTween extends Tween { DecorationTween({ Decoration begin, Decoration end }) : super(begin: begin, end: end); @@ -29,14 +29,14 @@ class DecorationTween extends Tween { } } -/// An animated value that interpolates [EdgeDims]. +/// An interpolation between two [EdgeDims]s. class EdgeDimsTween extends Tween { EdgeDimsTween({ EdgeDims begin, EdgeDims end }) : super(begin: begin, end: end); EdgeDims lerp(double t) => EdgeDims.lerp(begin, end, t); } -/// An animated value that interpolates [Matrix4]s. +/// An interpolation between two [Matrix4]s. /// /// Currently this class works only for translations. class Matrix4Tween extends Tween { @@ -78,12 +78,17 @@ abstract class AnimatedWidgetBase extends StatefulComponent { } } +/// Used by [AnimatedWidgetBaseState]. typedef Tween TweenConstructor(T targetValue); + +/// Used by [AnimatedWidgetBaseState]. typedef Tween TweenVisitor(Tween tween, T targetValue, TweenConstructor constructor); +/// A base class for widgets with implicit animations. abstract class AnimatedWidgetBaseState extends State { AnimationController _controller; + /// The animation driving this widget's implicit animations. Animation get animation => _animation; Animation _animation; diff --git a/packages/flutter/lib/src/widgets/locale_query.dart b/packages/flutter/lib/src/widgets/locale_query.dart index f6980bda50c..5e34e687db6 100644 --- a/packages/flutter/lib/src/widgets/locale_query.dart +++ b/packages/flutter/lib/src/widgets/locale_query.dart @@ -7,6 +7,7 @@ import 'framework.dart'; /// Superclass for locale-specific data provided by the application. class LocaleQueryData { } +/// Establishes a subtree in which locale queries resolve to the given data. class LocaleQuery extends InheritedWidget { LocaleQuery({ Key key, @@ -16,6 +17,7 @@ class LocaleQuery extends InheritedWidget { assert(child != null); } + /// The locale data for this subtree. final T data; /// The data from the closest instance of this class that encloses the given context. diff --git a/packages/flutter/lib/src/widgets/mimic.dart b/packages/flutter/lib/src/widgets/mimic.dart index 3af2ed080f8..0ae06a7fcfb 100644 --- a/packages/flutter/lib/src/widgets/mimic.dart +++ b/packages/flutter/lib/src/widgets/mimic.dart @@ -144,6 +144,9 @@ class Mimicable extends StatefulComponent { MimicableState createState() => new MimicableState(); } +/// The state for a [Mimicable]. +/// +/// Exposes an API for starting and stopping mimicking. class MimicableState extends State { Size _size; bool _beingMimicked = false; diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart index b045783ad79..f293c960e2b 100644 --- a/packages/flutter/lib/src/widgets/navigator.dart +++ b/packages/flutter/lib/src/widgets/navigator.dart @@ -5,11 +5,18 @@ import 'framework.dart'; import 'overlay.dart'; +/// An abstraction for an entry managed by a [Navigator]. +/// +/// This class defines an abstract interface between the navigator and the +/// "routes" that are pushed on and popped off the navigator. Most routes have +/// visual affordances, which they place in the navigators [Overlay] using one +/// or more [OverlayEntry] objects. abstract class Route { /// The navigator that the route is in, if any. NavigatorState get navigator => _navigator; NavigatorState _navigator; + /// The overlay entries for this route. List get overlayEntries => const []; /// Called when the route is inserted into the navigator. @@ -66,6 +73,7 @@ abstract class Route { } } +/// Data that might be useful in constructing a [Route]. class RouteSettings { const RouteSettings({ this.name, @@ -73,8 +81,20 @@ class RouteSettings { this.isInitialRoute: false }); + /// The name of the route (e.g., "/settings"). final String name; + + /// The set of keys that are most relevant for constructoring [Hero] + /// transitions. For example, if the current route contains a list of music + /// albums and the user triggered this navigation by tapping one of the + /// albums, the most valuable album cover is the one associated with the album + /// the user tapped and is the one that should heroically transition when + /// opening the details page for that album. final Set mostValuableKeys; + + /// Whether this route is the very first route being pushed onto this [Navigator]. + /// + /// The initial route typically skips any entrance transition to speed startup. final bool isInitialRoute; String toString() { @@ -88,17 +108,33 @@ class RouteSettings { } } +/// Creates a route for the given route settings. typedef Route RouteFactory(RouteSettings settings); + +/// A callback in during which you can perform a number of navigator operations (e.g., pop, push) that happen atomically. typedef void NavigatorTransactionCallback(NavigatorTransaction transaction); +/// An interface for observing the behavior of a [Navigator]. class NavigatorObserver { /// The navigator that the observer is observing, if any. NavigatorState get navigator => _navigator; NavigatorState _navigator; + + /// The [Navigator] pushed the given route. void didPush(Route route, Route previousRoute) { } + + /// THe [Navigator] popped the given route. void didPop(Route route, Route previousRoute) { } } +/// Manages a set of child widgets with a stack discipline. +/// +/// Many apps have a navigator near the top of their widget hierarchy in order +/// to display their logical history using an [Overlay] with the most recently +/// visited pages visually on top of the older pages. Using this pattern lets +/// the navigator visually transition from one page to another by the widgets +/// around in the overlay. Similarly, the navigator can be used to show a dialog +/// by positioning the dialog widget above the current page. class Navigator extends StatefulComponent { Navigator({ Key key, @@ -110,25 +146,72 @@ class Navigator extends StatefulComponent { assert(onGenerateRoute != null); } + /// The name of the first route to show. final String initialRoute; + + /// Called to generate a route for a given [RouteSettings]. final RouteFactory onGenerateRoute; + + /// Called when [onGenerateRoute] fails to generate a route. + /// + /// This callback is typically used for error handling. For example, this + /// callback might always generate a "not found" page that describes the route + /// that wasn't found. + /// + /// Unknown routes can arise either from errors in the app or from external + /// requests to push routes, such as from Android intents. final RouteFactory onUnknownRoute; + + /// An observer for this navigator. final NavigatorObserver observer; + /// The default name for the initial route. static const String defaultRouteName = '/'; + /// Push a named route onto the navigator that most tightly encloses the given context. + /// + /// The route name will be passed to that navigator's [onGenerateRoute] + /// callback. The returned route will be pushed into the navigator. The set of + /// most valuable keys will be used to construct an appropriate [Hero] transition. + /// + /// Uses [openTransaction()]. Only one transaction will be executed per frame. static void pushNamed(BuildContext context, String routeName, { Set mostValuableKeys }) { openTransaction(context, (NavigatorTransaction transaction) { transaction.pushNamed(routeName, mostValuableKeys: mostValuableKeys); }); } + /// Push a route onto the navigator that most tightly encloses the given context. + /// + /// Adds the given route to the Navigator's history, and transitions to it. + /// The route will have didPush() and didChangeNext() called on it; the + /// previous route, if any, will have didChangeNext() called on it; and the + /// Navigator observer, if any, will have didPush() called on it. + /// + /// Uses [openTransaction()]. Only one transaction will be executed per frame. static void push(BuildContext context, Route route) { openTransaction(context, (NavigatorTransaction transaction) { transaction.push(route); }); } + /// Pop a route off the navigator that most tightly encloses the given context. + /// + /// Tries to removes the current route, calling its didPop() method. If that + /// method returns false, then nothing else happens. Otherwise, the observer + /// (if any) is notified using its didPop() method, and the previous route is + /// notified using [Route.didChangeNext]. + /// + /// If non-null, [result] will be used as the result of the route. Routes + /// such as dialogs or popup menus typically use this mechanism to return the + /// value selected by the user to the widget that created their route. The + /// type of [result], if provided, must match the type argument of the class + /// of the current route. (In practice, this is usually "dynamic".) + /// + /// Returns true if a route was popped; returns false if there are no further + /// previous routes. + /// + /// Uses [openTransaction()]. Only one transaction will be executed per frame. static bool pop(BuildContext context, [ dynamic result ]) { bool returnValue; openTransaction(context, (NavigatorTransaction transaction) { @@ -137,17 +220,30 @@ class Navigator extends StatefulComponent { return returnValue; } + /// Calls pop() repeatedly until the given route is the current route. + /// If it is already the current route, nothing happens. + /// + /// Uses [openTransaction()]. Only one transaction will be executed per frame. static void popUntil(BuildContext context, Route targetRoute) { openTransaction(context, (NavigatorTransaction transaction) { transaction.popUntil(targetRoute); }); } + /// Whether the navigator that most tightly encloses the given context can be popped. + /// + /// The initial route cannot be popped off the navigator, which implies that + /// this function returns true only if popping the navigator would not remove + /// the initial route. static bool canPop(BuildContext context) { NavigatorState navigator = context.ancestorStateOfType(const TypeMatcher()); return navigator != null && navigator.canPop(); } + /// Executes a simple transaction that both pops the current route off and + /// pushes a named route into the navigator that most tightly encloses the given context. + /// + /// Uses [openTransaction()]. Only one transaction will be executed per frame. static void popAndPushNamed(BuildContext context, String routeName, { Set mostValuableKeys }) { openTransaction(context, (NavigatorTransaction transaction) { transaction.pop(); @@ -155,6 +251,12 @@ class Navigator extends StatefulComponent { }); } + /// Calls callback immediately to create a navigator transaction. + /// + /// To avoid race conditions, a navigator will execute at most one operation + /// per animation frame. If you wish to perform a compound change to the + /// navigator's state, you can use a navigator transaction to execute all the + /// changes atomically by making the changes inside the given callback. static void openTransaction(BuildContext context, NavigatorTransactionCallback callback) { NavigatorState navigator = context.ancestorStateOfType(const TypeMatcher()); assert(() { @@ -168,6 +270,7 @@ class Navigator extends StatefulComponent { NavigatorState createState() => new NavigatorState(); } +/// The state for a [Navigator] widget. class NavigatorState extends State { final GlobalKey _overlayKey = new GlobalKey(); final List _history = new List(); @@ -202,7 +305,7 @@ class NavigatorState extends State { assert(() { _debugLocked = false; return true; }); } - // Used by Routes and NavigatorObservers + /// The overlay this navigator uses for its visual presentation. OverlayState get overlay => _overlayKey.currentState; OverlayEntry get _currentOverlayEntry { @@ -344,6 +447,10 @@ class NavigatorState extends State { _pop(); } + /// Whether this navigator can be popped. + /// + /// The only route that cannot be popped off the navigator is the initial + /// route. bool canPop() { assert(_history.length > 0); return _history.length > 1 || _history[0].willHandlePopInternally; @@ -351,6 +458,12 @@ class NavigatorState extends State { bool _hadTransaction = true; + /// Calls callback immediately to create a navigator transaction. + /// + /// To avoid race conditions, a navigator will execute at most one operation + /// per animation frame. If you wish to perform a compound change to the + /// navigator's state, you can use a navigator transaction to execute all the + /// changes atomically by making the changes inside the given callback. bool openTransaction(NavigatorTransactionCallback callback) { assert(callback != null); if (_hadTransaction) @@ -375,6 +488,7 @@ class NavigatorState extends State { } } +/// A sequence of [Navigator] operations that are executed atomically. class NavigatorTransaction { NavigatorTransaction._(this._navigator) { assert(_navigator != null); @@ -382,8 +496,9 @@ class NavigatorTransaction { NavigatorState _navigator; bool _debugOpen = true; - /// Invokes the Navigator's onGenerateRoute callback to create a route with - /// the given name, then calls [push()] with that route. + /// The route name will be passed to the navigator's [onGenerateRoute] + /// callback. The returned route will be pushed into the navigator. The set of + /// most valuable keys will be used to construct an appropriate [Hero] transition. void pushNamed(String name, { Set mostValuableKeys }) { assert(_debugOpen); _navigator._pushNamed(name, mostValuableKeys: mostValuableKeys); @@ -439,9 +554,11 @@ class NavigatorTransaction { /// (if any) is notified using its didPop() method, and the previous route is /// notified using [Route.didChangeNext]. /// - /// The type of the result argument, if provided, must match the type argument - /// of the class of the current route. (In practice, this is usually - /// "dynamic".) + /// If non-null, [result] will be used as the result of the route. Routes + /// such as dialogs or popup menus typically use this mechanism to return the + /// value selected by the user to the widget that created their route. The + /// type of [result], if provided, must match the type argument of the class + /// of the current route. (In practice, this is usually "dynamic".) /// /// Returns true if a route was popped; returns false if there are no further /// previous routes. diff --git a/packages/flutter/lib/src/widgets/notification_listener.dart b/packages/flutter/lib/src/widgets/notification_listener.dart index 125edcd3db1..021a4e31558 100644 --- a/packages/flutter/lib/src/widgets/notification_listener.dart +++ b/packages/flutter/lib/src/widgets/notification_listener.dart @@ -7,7 +7,9 @@ import 'framework.dart'; /// Return true to cancel the notification bubbling. typedef bool NotificationListenerCallback(T notification); +/// A notification that can bubble up the widget tree. abstract class Notification { + /// Start bubbling this notification at the given build context. void dispatch(BuildContext target) { target.visitAncestorElements((Element element) { if (element is StatelessComponentElement && @@ -21,6 +23,7 @@ abstract class Notification { } } +/// Listens for [Notification]s bubbling up the tree. class NotificationListener extends StatelessComponent { NotificationListener({ Key key, @@ -29,6 +32,8 @@ class NotificationListener extends StatelessComponent { }) : super(key: key); final Widget child; + + /// Called when a notification of the appropriate type arrives at this location in the tree. final NotificationListenerCallback onNotification; bool _dispatch(Notification notification) { diff --git a/packages/flutter/lib/src/widgets/page_storage.dart b/packages/flutter/lib/src/widgets/page_storage.dart index 520814f1534..b1587f2ec00 100644 --- a/packages/flutter/lib/src/widgets/page_storage.dart +++ b/packages/flutter/lib/src/widgets/page_storage.dart @@ -37,6 +37,10 @@ class _StorageEntryIdentifier { } } +/// A storage bucket associated with a page in an app. +/// +/// Useful for storing per-page state that persists across navigations from one +/// page to another. class PageStorageBucket { _StorageEntryIdentifier _computeStorageIdentifier(BuildContext context) { _StorageEntryIdentifier result = new _StorageEntryIdentifier(); @@ -62,15 +66,22 @@ class PageStorageBucket { } Map<_StorageEntryIdentifier, dynamic> _storage; + + /// Write the given data into this page storage bucket using an identifier + /// computed from the given context. void writeState(BuildContext context, dynamic data) { _storage ??= <_StorageEntryIdentifier, dynamic>{}; _storage[_computeStorageIdentifier(context)] = data; } + + /// Read given data from into this page storage bucket using an identifier + /// computed from the given context. dynamic readState(BuildContext context) { return _storage != null ? _storage[_computeStorageIdentifier(context)] : null; } } +/// Establishes a page storage bucket for this widget subtree. class PageStorage extends StatelessComponent { PageStorage({ Key key, @@ -79,6 +90,8 @@ class PageStorage extends StatelessComponent { }) : super(key: key); final Widget child; + + /// The page storage bucket to use for this subtree. final PageStorageBucket bucket; /// The bucket from the closest instance of this class that encloses the given context.