Unverified Commit 81baee43 authored by Dwayne Slater's avatar Dwayne Slater Committed by GitHub

Configurable padding around FocusNodes in Scrollables (#96815)

parent 82d4dbb6
...@@ -759,6 +759,16 @@ class FocusNode with DiagnosticableTreeMixin, ChangeNotifier { ...@@ -759,6 +759,16 @@ class FocusNode with DiagnosticableTreeMixin, ChangeNotifier {
return null; return null;
} }
/// Returns the amount of additional space to reveal around the attached widget
/// when focused inside a scrolling container via [Scrollable.ensureVisible].
///
/// For example, a value of `EdgeInsets.all(16.0)` ensures 16 pixels of
/// the adjacent widget are visible when this node receives focus.
///
/// By default, this returns [FocusManager.defaultEnsureVisiblePadding] from the
/// associated [FocusManager], or [EdgeInsets.zero].
EdgeInsets get ensureVisiblePadding => _manager?.defaultEnsureVisiblePadding ?? EdgeInsets.zero;
/// Returns the size of the attached widget's [RenderObject], in logical /// Returns the size of the attached widget's [RenderObject], in logical
/// units. /// units.
/// ///
...@@ -1710,6 +1720,20 @@ class FocusManager with DiagnosticableTreeMixin, ChangeNotifier { ...@@ -1710,6 +1720,20 @@ class FocusManager with DiagnosticableTreeMixin, ChangeNotifier {
return handled; return handled;
} }
/// The default amount of additonal space to reveal when a widget is focused
/// inside a scrolling container via [Scrollable.ensureVisible].
///
/// Defaults to [EdgeInsets.zero], which does not add any additional space
/// when widgets are revealed.
///
/// For example, a value of `EdgeInsets.all(16.0)` ensures 16 pixels of
/// the adjacent widget are visible when focusing a widget inside of a
/// scrolling container.
///
/// Individual [FocusNode]s may increase or decrease this padding, use
/// [FocusNode.ensureVisiblePadding] to obtain a node's desired padding.
EdgeInsets defaultEnsureVisiblePadding = EdgeInsets.zero;
/// The node that currently has the primary focus. /// The node that currently has the primary focus.
FocusNode? get primaryFocus => _primaryFocus; FocusNode? get primaryFocus => _primaryFocus;
FocusNode? _primaryFocus; FocusNode? _primaryFocus;
......
...@@ -36,7 +36,7 @@ void _focusAndEnsureVisible( ...@@ -36,7 +36,7 @@ void _focusAndEnsureVisible(
ScrollPositionAlignmentPolicy alignmentPolicy = ScrollPositionAlignmentPolicy.explicit, ScrollPositionAlignmentPolicy alignmentPolicy = ScrollPositionAlignmentPolicy.explicit,
}) { }) {
node.requestFocus(); node.requestFocus();
Scrollable.ensureVisible(node.context!, alignment: 1.0, alignmentPolicy: alignmentPolicy); Scrollable.ensureVisible(node.context!, alignment: 1.0, padding: node.ensureVisiblePadding, alignmentPolicy: alignmentPolicy);
} }
// A class to temporarily hold information about FocusTraversalGroups when // A class to temporarily hold information about FocusTraversalGroups when
......
...@@ -346,6 +346,7 @@ class _PagePosition extends ScrollPositionWithSingleContext implements PageMetri ...@@ -346,6 +346,7 @@ class _PagePosition extends ScrollPositionWithSingleContext implements PageMetri
Future<void> ensureVisible( Future<void> ensureVisible(
RenderObject object, { RenderObject object, {
double alignment = 0.0, double alignment = 0.0,
EdgeInsets padding = EdgeInsets.zero,
Duration duration = Duration.zero, Duration duration = Duration.zero,
Curve curve = Curves.ease, Curve curve = Curves.ease,
ScrollPositionAlignmentPolicy alignmentPolicy = ScrollPositionAlignmentPolicy.explicit, ScrollPositionAlignmentPolicy alignmentPolicy = ScrollPositionAlignmentPolicy.explicit,
......
...@@ -676,6 +676,10 @@ abstract class ScrollPosition extends ViewportOffset with ScrollMetrics { ...@@ -676,6 +676,10 @@ abstract class ScrollPosition extends ViewportOffset with ScrollMetrics {
/// Animates the position such that the given object is as visible as possible /// Animates the position such that the given object is as visible as possible
/// by just scrolling this position. /// by just scrolling this position.
/// ///
/// The [padding] is used to add extra space around the [object] when revealing it.
/// For example, `EdgeInsets.only(bottom: 16.0)` will ensure an additional 16 pixels
/// of space are visible below the [object].
///
/// The optional `targetRenderObject` parameter is used to determine which area /// The optional `targetRenderObject` parameter is used to determine which area
/// of that object should be as visible as possible. If `targetRenderObject` /// of that object should be as visible as possible. If `targetRenderObject`
/// is null, the entire [RenderObject] (as defined by its /// is null, the entire [RenderObject] (as defined by its
...@@ -686,9 +690,12 @@ abstract class ScrollPosition extends ViewportOffset with ScrollMetrics { ...@@ -686,9 +690,12 @@ abstract class ScrollPosition extends ViewportOffset with ScrollMetrics {
/// ///
/// * [ScrollPositionAlignmentPolicy] for the way in which `alignment` is /// * [ScrollPositionAlignmentPolicy] for the way in which `alignment` is
/// applied, and the way the given `object` is aligned. /// applied, and the way the given `object` is aligned.
/// * [FocusNode.ensureVisiblePadding] which specifies the [padding] used when
/// a widget is focused via focus traversal.
Future<void> ensureVisible( Future<void> ensureVisible(
RenderObject object, { RenderObject object, {
double alignment = 0.0, double alignment = 0.0,
EdgeInsets padding = EdgeInsets.zero,
Duration duration = Duration.zero, Duration duration = Duration.zero,
Curve curve = Curves.ease, Curve curve = Curves.ease,
ScrollPositionAlignmentPolicy alignmentPolicy = ScrollPositionAlignmentPolicy.explicit, ScrollPositionAlignmentPolicy alignmentPolicy = ScrollPositionAlignmentPolicy.explicit,
...@@ -699,14 +706,18 @@ abstract class ScrollPosition extends ViewportOffset with ScrollMetrics { ...@@ -699,14 +706,18 @@ abstract class ScrollPosition extends ViewportOffset with ScrollMetrics {
final RenderAbstractViewport viewport = RenderAbstractViewport.of(object)!; final RenderAbstractViewport viewport = RenderAbstractViewport.of(object)!;
assert(viewport != null); assert(viewport != null);
Rect? targetRect; Rect targetRect;
if (targetRenderObject != null && targetRenderObject != object) { if (targetRenderObject != null && targetRenderObject != object) {
targetRect = MatrixUtils.transformRect( targetRect = MatrixUtils.transformRect(
targetRenderObject.getTransformTo(object), targetRenderObject.getTransformTo(object),
object.paintBounds.intersect(targetRenderObject.paintBounds), object.paintBounds.intersect(targetRenderObject.paintBounds),
); );
} else {
targetRect = object.paintBounds;
} }
targetRect = padding.inflateRect(targetRect);
double target; double target;
switch (alignmentPolicy) { switch (alignmentPolicy) {
case ScrollPositionAlignmentPolicy.explicit: case ScrollPositionAlignmentPolicy.explicit:
......
...@@ -311,9 +311,19 @@ class Scrollable extends StatefulWidget { ...@@ -311,9 +311,19 @@ class Scrollable extends StatefulWidget {
/// Scrolls the scrollables that enclose the given context so as to make the /// Scrolls the scrollables that enclose the given context so as to make the
/// given context visible. /// given context visible.
///
/// The [padding] is used to add extra space around the [context]'s
/// associated widget when revealing it. For example, `EdgeInsets.only(bottom: 16.0)`
/// will ensure an additional 16 pixels of space are visible below the widget.
///
/// See also:
///
/// * [FocusNode.ensureVisiblePadding] which specifies the [padding] used when
/// a widget is focused via focus traversal.
static Future<void> ensureVisible( static Future<void> ensureVisible(
BuildContext context, { BuildContext context, {
double alignment = 0.0, double alignment = 0.0,
EdgeInsets padding = EdgeInsets.zero,
Duration duration = Duration.zero, Duration duration = Duration.zero,
Curve curve = Curves.ease, Curve curve = Curves.ease,
ScrollPositionAlignmentPolicy alignmentPolicy = ScrollPositionAlignmentPolicy.explicit, ScrollPositionAlignmentPolicy alignmentPolicy = ScrollPositionAlignmentPolicy.explicit,
...@@ -332,6 +342,7 @@ class Scrollable extends StatefulWidget { ...@@ -332,6 +342,7 @@ class Scrollable extends StatefulWidget {
futures.add(scrollable.position.ensureVisible( futures.add(scrollable.position.ensureVisible(
context.findRenderObject()!, context.findRenderObject()!,
alignment: alignment, alignment: alignment,
padding: padding,
duration: duration, duration: duration,
curve: curve, curve: curve,
alignmentPolicy: alignmentPolicy, alignmentPolicy: alignmentPolicy,
......
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