Commit af170c8e authored by Adam Barth's avatar Adam Barth Committed by GitHub

Add more dartdocs (#9183)

Mostly related to semantics and scrolling.
parent f46dd406
......@@ -862,6 +862,22 @@ class _ForkingSemanticsFragment extends _SemanticsFragment {
}
}
/// A reference to the semantics tree.
///
/// The framework maintains the semantics tree (used for accessibility and
/// indexing) only when there is at least one client holding an open
/// [SemanticsHandle].
///
/// The framework notifies the client that it has updated the semantics tree by
/// calling the [listener] callback. When the client no longer needs the
/// semantics tree, the client can call [dispose] on the [SemanticsHandle],
/// which stops these callbacks and closes the [SemanticsHandle]. When all the
/// outstanding [SemanticsHandle] objects are closed, the framework stops
/// updating the semantics tree.
///
/// To obtain a [SemanticsHandle], call [PipelineOwner.ensureSemantics] on the
/// [PipelineOwner] for the render tree from which you wish to read semantics.
/// You can obtain the [PipelineOwner] using the [RenderObject.owner] property.
class SemanticsHandle {
SemanticsHandle._(this._owner, this.listener) {
assert(_owner != null);
......@@ -870,8 +886,16 @@ class SemanticsHandle {
}
PipelineOwner _owner;
/// The callback that will be notified when the semantics tree updates.
final VoidCallback listener;
/// Closes the semantics handle and stops calling [listener] when the
/// semantics updates.
///
/// When all the outstanding [SemanticsHandle] objects for a given
/// [PipelineOwner] are closed, the [PipelineOwner] will stop updating the
/// semantics tree.
@mustCallSuper
void dispose() {
assert(() {
......@@ -1096,6 +1120,18 @@ class PipelineOwner {
int _outstandingSemanticsHandle = 0;
/// Opens a [SemanticsHandle] and calls [listener] whenever the semantics tree
/// updates.
///
/// The [PipelineOwner] updates the semantics tree only when there are clients
/// that wish to use the semantics tree. These clients express their interest
/// by holding [SemanticsHandle] objects that notify them whenever the
/// semantics tree updates.
///
/// Clients can close their [SemanticsHandle] by calling
/// [SemanticsHandle.dispose]. Once all the outstanding [SemanticsHandle]
/// objects for a given [PipelineOwner] are closed, the [PipelineOwner] stops
/// maintaining the semantics tree.
SemanticsHandle ensureSemantics({ VoidCallback listener }) {
if (_outstandingSemanticsHandle++ == 0) {
assert(_semanticsOwner == null);
......
......@@ -21,7 +21,7 @@ import 'viewport_offset.dart';
/// the framework recognize such render objects and interact with them without
/// having specific knowledge of all the various types of viewports.
abstract class RenderAbstractViewport implements RenderObject {
/// Returns the [RenderAbstractViewport] that most closely encloses the given
/// Returns the [RenderAbstractViewport] that most tightly encloses the given
/// render object.
///
/// If the object does not have a [RenderAbstractViewport] as an ancestor,
......
......@@ -7,24 +7,24 @@ import 'dart:async';
import 'package:flutter/foundation.dart';
/// A leaf node in the focus tree that can receive focus.
///
///
/// The focus tree keeps track of which widget is the user's current focus. The
/// focused widget often listens for keyboard events.
///
///
/// To request focus, find the [FocusScopeNode] for the current [BuildContext]
/// and call the [FocusScopeNode.requestFocus] method:
///
///
/// ```dart
/// FocusScope.of(context).requestFocus(focusNode);
/// ```
///
///
/// If your widget requests focus, be sure to call
/// `FocusScope.of(context).reparentIfNeeded(focusNode);` in your `build`
/// method to reparent your [FocusNode] if your widget moves from one
/// location in the tree to another.
///
///
/// See also:
///
///
/// * [FocusScopeNode], which is an interior node in the focus tree.
/// * [FocusScope.of], which provides the [FocusScopeNode] for a given
/// [BuildContext].
......@@ -33,25 +33,25 @@ class FocusNode extends ChangeNotifier {
FocusManager _manager;
/// Whether this node has the overall focus.
///
///
/// A [FocusNode] has the overall focus when the node is focused in its
/// parent [FocusScopeNode] and [FocusScopeNode.isFirstFocus] is true for
/// that scope and all its ancestor scopes.
///
///
/// To request focus, find the [FocusScopeNode] for the current [BuildContext]
/// and call the [FocusScopeNode.requestFocus] method:
///
///
/// ```dart
/// FocusScope.of(context).requestFocus(focusNode);
/// ```
///
///
/// This object notifies its listeners whenever this value changes.
bool get hasFocus => _manager?._currentFocus == this;
/// Cancels any oustanding requests for focus.
///
/// Cancels any outstanding requests for focus.
///
/// This method is safe to call regardless of whether this node has ever
/// requested focus.
/// requested focus.
void unfocus() {
_parent?._resignFocus(this);
assert(_parent == null);
......@@ -76,21 +76,21 @@ class FocusNode extends ChangeNotifier {
}
/// An interior node in the focus tree.
///
///
/// The focus tree keeps track of which widget is the user's current focus. The
/// focused widget often listens for keyboard events.
///
///
/// The interior nodes in the focus tree cannot themselves be focused but
/// instead remember previous focus states. A scope is currently active in its
/// parent whenever [isFirstFocus] is true. If that scope is detached from its
/// parent, its previous sibling becomes the parent's first focus.
///
///
/// A [FocusNode] has the overall focus when the node is focused in its
/// parent [FocusScopeNode] and [FocusScopeNode.isFirstFocus] is true for
/// that scope and all its ancestor scopes.
///
///
/// See also:
///
///
/// * [FocusNode], which is a leaf node in the focus tree that can receive
/// focus.
/// * [FocusScope.of], which provides the [FocusScopeNode] for a given
......@@ -206,10 +206,10 @@ class FocusScopeNode extends Object with TreeDiagnosticsMixin {
}
/// Requests that the given node becomes the focus for this scope.
///
///
/// If the given node is currently focused in another scope, the node will
/// first be unfocused in that scope.
///
///
/// The node will receive the overall focus if this [isFirstFocus] is true
/// in this scope and all its ancestor scopes. The node is notified that it
/// has received the overall focus in a microtask.
......@@ -228,10 +228,10 @@ class FocusScopeNode extends Object with TreeDiagnosticsMixin {
/// If this scope lacks a focus, request that the given node becomes the
/// focus.
///
///
/// Useful for widgets that wish to grab the focus if no other widget already
/// has the focus.
///
///
/// The node is notified that it has received the overall focus in a
/// microtask.
void autofocus(FocusNode node) {
......@@ -241,7 +241,7 @@ class FocusScopeNode extends Object with TreeDiagnosticsMixin {
}
/// Adopts the given node if it is focused in another scope.
///
///
/// A widget that requests that a node is focused should call this method
/// during its `build` method in case the widget is moved from one location
/// in the tree to another location that has a different focus scope.
......@@ -265,7 +265,7 @@ class FocusScopeNode extends Object with TreeDiagnosticsMixin {
}
/// Makes the given child the first focus of this scope.
///
///
/// If the child has another parent scope, the child is first removed from
/// that scope. After this method returns [isFirstFocus] will be true for
/// the child.
......@@ -281,12 +281,12 @@ class FocusScopeNode extends Object with TreeDiagnosticsMixin {
}
/// Adopts the given scope if it is the first focus of another scope.
///
///
/// A widget that sets a scope as the first focus of another scope should
/// call this method during its `build` method in case the widget is moved
/// from one location in the tree to another location that has a different
/// focus scope.
///
///
/// If the given scope is not the first focus of its old parent, the scope
/// is simply detached from its old parent.
void reparentScopeIfNeeded(FocusScopeNode child) {
......@@ -300,9 +300,9 @@ class FocusScopeNode extends Object with TreeDiagnosticsMixin {
}
/// Remove this scope from its parent child list.
///
///
/// This method is safe to call even if this scope does not have a parent.
///
///
/// A widget that sets a scope as the first focus of another scope should
/// call this method during [State.dispose] to avoid leaving dangling
/// children in their parent scope.
......@@ -343,18 +343,18 @@ class FocusScopeNode extends Object with TreeDiagnosticsMixin {
///
/// The focus tree keeps track of which widget is the user's current focus. The
/// focused widget often listens for keyboard events.
///
///
/// The focus manager is responsible for holding the [FocusScopeNode] that is
/// the root of the focus tree and tracking which [FocusNode] has the overall
/// focus.
///
///
/// The [FocusManager] is held by the [WidgetBinding] as
/// [WidgetBinding.focusManager]. The [FocusManager] is rarely accessed
/// directly. Instead, to find the [FocusScopeNode] for a given [BuildContext],
/// use [FocusScope.of].
///
/// See also:
///
///
/// * [FocusNode], which is a leaf node in the focus tree that can receive
/// focus.
/// * [FocusScopeNode], which is an interior node in the focus tree.
......@@ -362,7 +362,7 @@ class FocusScopeNode extends Object with TreeDiagnosticsMixin {
/// [BuildContext].
class FocusManager {
/// Creates an object that manages the focus tree.
///
///
/// This constructor is rarely called directly. To access the [FocusManager],
/// consider using [WidgetBinding.focusManager] instead.
FocusManager() {
......@@ -372,7 +372,7 @@ class FocusManager {
}
/// The root [FocusScopeNode] in the focus tree.
///
///
/// This field is rarely used direction. Instead, to find the
/// [FocusScopeNode] for a given [BuildContext], use [FocusScope.of].
final FocusScopeNode rootScope = new FocusScopeNode();
......
......@@ -27,31 +27,31 @@ class _FocusScopeMarker extends InheritedWidget {
}
/// Establishes a scope in which widgets can receive focus.
///
///
/// The focus tree keeps track of which widget is the user's current focus. The
/// focused widget often listens for keyboard events.
///
///
/// The a focus scope does not itself receive focus but instead helps remember
/// previous focus states. A scope is currently active when its [node] is the
/// first focus of its parent scope. To activate a [FocusScope], either use the
/// [autofocus] property or explicitly make the [node] the first focus in the
/// parent scope:
///
///
/// ```dart
/// FocusScope.of(context).setFirstFocus(node);
/// ```
///
///
/// When a [FocusScope] is removed from the tree, the previously active
/// [FocusScope] becomes active again.
///
///
/// See also:
///
///
/// * [FocusScopeNode], which is the associated node in the focus tree.
/// * [FocusNode], which is a leaf node in the focus tree that can receive
/// focus.
class FocusScope extends StatefulWidget {
/// Creates a scope in which widgets can receive focus.
///
///
/// The [node] argument must not be null.
FocusScope({
Key key,
......@@ -73,6 +73,8 @@ class FocusScope extends StatefulWidget {
/// The widget below this widget in the tree.
final Widget child;
/// Returns the [node] of the [FocusScope] that most tightly encloses the
/// given [BuildContext].
static FocusScopeNode of(BuildContext context) {
final _FocusScopeMarker scope = context.inheritFromWidgetOfExactType(_FocusScopeMarker);
return scope?.node ?? WidgetsBinding.instance.focusManager.rootScope;
......
......@@ -24,6 +24,9 @@ import 'viewport.dart';
/// A controller for [PageView].
///
/// A page controller lets you manipulate which page is visible in a [PageView].
/// In addition to being able to control the pixel offset of the content inside
/// the [PageView], a [PageController] also lets you control the offset in terms
/// of pages, which are increments of the viewport size.
///
/// See also:
///
......@@ -252,14 +255,33 @@ final PageController _defaultPageController = new PageController();
const PageScrollPhysics _kPagePhysics = const PageScrollPhysics();
/// A scrollable list that works page by page.
// TODO(ianh): More documentation here.
///
/// Each child of a page view is forced to be the same size as the viewport.
///
/// You can use a [PageController] to control which page is visible in the view.
/// In addition to being able to control the pixel offset of the content inside
/// the [PageView], a [PageController] also lets you control the offset in terms
/// of pages, which are increments of the viewport size.
///
/// The [PageController] can also be used to control the
/// [PageController.initialPage], which determines which page is shown when the
/// [PageView] is first constructed, and the [PageController.viewportFraction],
/// which determines the size of the pages as a fraction of the viewport size.
///
/// See also:
///
/// * [SingleChildScrollView], when you need to make a single child scrollable.
/// * [ListView], for a scrollable list of boxes.
/// * [GridView], for a scrollable grid of boxes.
/// * [PageController], which controls which page is visible in the view.
/// * [SingleChildScrollView], when you need to make a single child scrollable.
/// * [ListView], for a scrollable list of boxes.
/// * [GridView], for a scrollable grid of boxes.
class PageView extends StatefulWidget {
/// Creates a scrollable list that works page by page from an explicit [List]
/// of widgets.
///
/// This constructor is appropriate for page views with a small number of
/// children because constructing the [List] requires doing work for every
/// child that could possibly be displayed in the page view, instead of just
/// those children that are actually visible.
PageView({
Key key,
this.scrollDirection: Axis.horizontal,
......@@ -272,6 +294,18 @@ class PageView extends StatefulWidget {
childrenDelegate = new SliverChildListDelegate(children),
super(key: key);
/// Creates a scrollable list that works page by page using widgets that are
/// created on demand.
///
/// This constructor is appropriate for page views with a large (or infinite)
/// number of children because the builder is called only for those children
/// that are actually visible.
///
/// Providing a non-null [itemCount] lets the [PageView] compute the maximum
/// scroll extent.
///
/// [itemBuilder] will be called only with indices greater than or equal to
/// zero and less than [itemCount].
PageView.builder({
Key key,
this.scrollDirection: Axis.horizontal,
......@@ -285,6 +319,8 @@ class PageView extends StatefulWidget {
childrenDelegate = new SliverChildBuilderDelegate(itemBuilder, childCount: itemCount),
super(key: key);
/// Creates a scrollable list that works page by page with a custom child
/// model.
PageView.custom({
Key key,
this.scrollDirection: Axis.horizontal,
......@@ -297,16 +333,49 @@ class PageView extends StatefulWidget {
assert(childrenDelegate != null);
}
/// The axis along which the page view scrolls.
///
/// Defaults to [Axis.horizontal].
final Axis scrollDirection;
/// Whether the page view scrolls in the reading direction.
///
/// For example, if the reading direction is left-to-right and
/// [scrollDirection] is [Axis.horizontal], then the page view scrolls from
/// left to right when [reverse] is false and from right to left when
/// [reverse] is true.
///
/// Similarly, if [scrollDirection] is [Axis.vertical], then the page view
/// scrolls from top to bottom when [reverse] is false and from bottom to top
/// when [reverse] is true.
///
/// Defaults to false.
final bool reverse;
/// An object that can be used to control the position to which this page
/// view is scrolled.
final PageController controller;
/// How the page view should respond to user input.
///
/// For example, determines how the page view continues to animate after the
/// user stops dragging the page view.
///
/// The physics are modified to snap to page boundaries using
/// [PageScrollPhysics] prior to being used.
///
/// Defaults to matching platform conventions.
final ScrollPhysics physics;
/// Called whenever the page in the center of the viewport changes.
final ValueChanged<int> onPageChanged;
/// A delegate that provides the children for the [PageView].
///
/// The [PageView.custom] constructor lets you specify this delegate
/// explicitly. The [PageView] and [PageView.builder] constructors create a
/// [childrenDelegate] that wraps the given [List] and [IndexedWidgetBuilder],
/// respectively.
final SliverChildDelegate childrenDelegate;
@override
......
......@@ -61,6 +61,16 @@ class ScrollBehavior {
return null;
}
/// Called whenever a [ScrollConfiguration] is rebuilt with a new
/// [ScrollBehavior] of the same [runtimeType].
///
/// If the new instance represents different information than the old
/// instance, then the method should return true, otherwise it should return
/// false.
///
/// If this method returns true, all the widgets that inherit from the
/// [ScrollConfiguration] will rebuild using the new [ScrollBehavior]. If this
/// method returns false, the rebuilds might be optimized away.
bool shouldNotify(covariant ScrollBehavior oldDelegate) => false;
}
......@@ -88,9 +98,9 @@ class ScrollConfiguration extends InheritedWidget {
}
@override
bool updateShouldNotify(ScrollConfiguration old) {
bool updateShouldNotify(ScrollConfiguration oldWidget) {
assert(behavior != null);
return behavior.runtimeType != old.behavior.runtimeType
|| behavior.shouldNotify(old.behavior);
return behavior.runtimeType != oldWidget.behavior.runtimeType
|| (behavior != oldWidget.behavior && behavior.shouldNotify(oldWidget.behavior));
}
}
......@@ -75,7 +75,7 @@ abstract class ScrollView extends StatelessWidget {
/// left to right when [reverse] is false and from right to left when
/// [reverse] is true.
///
/// Similarly, if [scrollDirection] is [Axis.vertical], then scroll view
/// Similarly, if [scrollDirection] is [Axis.vertical], then the scroll view
/// scrolls from top to bottom when [reverse] is false and from bottom to top
/// when [reverse] is true.
///
......
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