parent
f46dd406c1
commit
af170c8e56
@ -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.
|
||||
///
|
||||
|
Loading…
x
Reference in New Issue
Block a user