Unverified Commit 06adde0b authored by Tong Mu's avatar Tong Mu Committed by GitHub

Nested InkWells only show the innermost splash (#56611)

parent 0786f29f
......@@ -174,6 +174,29 @@ abstract class InteractiveInkFeatureFactory {
});
}
abstract class _ParentInkResponseState {
void markChildInkResponsePressed(_ParentInkResponseState childState, bool value);
}
class _ParentInkResponseProvider extends InheritedWidget {
const _ParentInkResponseProvider({
this.state,
Widget child,
}) : super(child: child);
final _ParentInkResponseState state;
@override
bool updateShouldNotify(_ParentInkResponseProvider oldWidget) => state != oldWidget.state;
static _ParentInkResponseState of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<_ParentInkResponseProvider>()?.state;
}
}
typedef _GetRectCallback = RectCallback Function(RenderBox referenceBox);
typedef _CheckContext = bool Function(BuildContext context);
/// An area of a [Material] that responds to touch. Has a configurable shape and
/// can be configured to clip splashes that extend outside its bounds or not.
///
......@@ -255,7 +278,7 @@ abstract class InteractiveInkFeatureFactory {
/// * [GestureDetector], for listening for gestures without ink splashes.
/// * [RaisedButton] and [FlatButton], two kinds of buttons in material design.
/// * [IconButton], which combines [InkResponse] with an [Icon].
class InkResponse extends StatefulWidget {
class InkResponse extends StatelessWidget {
/// Creates an area of a [Material] that responds to touch.
///
/// Must have an ancestor [Material] widget in which to cause ink reactions.
......@@ -508,6 +531,40 @@ class InkResponse extends StatefulWidget {
/// slightly more efficient).
RectCallback getRectCallback(RenderBox referenceBox) => null;
@override
Widget build(BuildContext context) {
final _ParentInkResponseState parentState = _ParentInkResponseProvider.of(context);
return _InnerInkResponse(
child: child,
onTap: onTap,
onTapDown: onTapDown,
onTapCancel: onTapCancel,
onDoubleTap: onDoubleTap,
onLongPress: onLongPress,
onHighlightChanged: onHighlightChanged,
onHover: onHover,
containedInkWell: containedInkWell,
highlightShape: highlightShape,
radius: radius,
borderRadius: borderRadius,
customBorder: customBorder,
focusColor: focusColor,
hoverColor: hoverColor,
highlightColor: highlightColor,
splashColor: splashColor,
splashFactory: splashFactory,
enableFeedback: enableFeedback,
excludeFromSemantics: excludeFromSemantics,
focusNode: focusNode,
canRequestFocus: canRequestFocus,
onFocusChange: onFocusChange,
autofocus: autofocus,
parentState: parentState,
getRectCallback: getRectCallback,
debugCheckContext: debugCheckContext,
);
}
/// Asserts that the given context satisfies the prerequisites for
/// this class.
///
......@@ -521,9 +578,74 @@ class InkResponse extends StatefulWidget {
assert(debugCheckHasDirectionality(context));
return true;
}
}
class _InnerInkResponse extends StatefulWidget {
const _InnerInkResponse({
this.child,
this.onTap,
this.onTapDown,
this.onTapCancel,
this.onDoubleTap,
this.onLongPress,
this.onHighlightChanged,
this.onHover,
this.containedInkWell = false,
this.highlightShape = BoxShape.circle,
this.radius,
this.borderRadius,
this.customBorder,
this.focusColor,
this.hoverColor,
this.highlightColor,
this.splashColor,
this.splashFactory,
this.enableFeedback = true,
this.excludeFromSemantics = false,
this.focusNode,
this.canRequestFocus = true,
this.onFocusChange,
this.autofocus = false,
this.parentState,
this.getRectCallback,
this.debugCheckContext,
}) : assert(containedInkWell != null),
assert(highlightShape != null),
assert(enableFeedback != null),
assert(excludeFromSemantics != null),
assert(autofocus != null),
assert(canRequestFocus != null);
final Widget child;
final GestureTapCallback onTap;
final GestureTapDownCallback onTapDown;
final GestureTapCallback onTapCancel;
final GestureTapCallback onDoubleTap;
final GestureLongPressCallback onLongPress;
final ValueChanged<bool> onHighlightChanged;
final ValueChanged<bool> onHover;
final bool containedInkWell;
final BoxShape highlightShape;
final double radius;
final BorderRadius borderRadius;
final ShapeBorder customBorder;
final Color focusColor;
final Color hoverColor;
final Color highlightColor;
final Color splashColor;
final InteractiveInkFeatureFactory splashFactory;
final bool enableFeedback;
final bool excludeFromSemantics;
final ValueChanged<bool> onFocusChange;
final bool autofocus;
final FocusNode focusNode;
final bool canRequestFocus;
final _ParentInkResponseState parentState;
final _GetRectCallback getRectCallback;
final _CheckContext debugCheckContext;
@override
_InkResponseState<InkResponse> createState() => _InkResponseState<InkResponse>();
_InkResponseState createState() => _InkResponseState();
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
......@@ -554,7 +676,9 @@ enum _HighlightType {
focus,
}
class _InkResponseState<T extends InkResponse> extends State<T> with AutomaticKeepAliveClientMixin<T> {
class _InkResponseState extends State<_InnerInkResponse>
with AutomaticKeepAliveClientMixin<_InnerInkResponse>
implements _ParentInkResponseState {
Set<InteractiveInkFeature> _splashes;
InteractiveInkFeature _currentSplash;
bool _hovering = false;
......@@ -563,6 +687,23 @@ class _InkResponseState<T extends InkResponse> extends State<T> with AutomaticKe
bool get highlightsExist => _highlights.values.where((InkHighlight highlight) => highlight != null).isNotEmpty;
final ObserverList<_ParentInkResponseState> _activeChildren = ObserverList<_ParentInkResponseState>();
@override
void markChildInkResponsePressed(_ParentInkResponseState childState, bool value) {
assert(childState != null);
final bool lastAnyPressed = _anyChildInkResponsePressed;
if (value) {
_activeChildren.add(childState);
} else {
_activeChildren.remove(childState);
}
final bool nowAnyPressed = _anyChildInkResponsePressed;
if (nowAnyPressed != lastAnyPressed) {
widget.parentState?.markChildInkResponsePressed(this, nowAnyPressed);
}
}
bool get _anyChildInkResponsePressed => _activeChildren.isNotEmpty;
void _handleAction(ActivateIntent intent) {
_startSplash(context: context);
_handleTap(context);
......@@ -578,7 +719,7 @@ class _InkResponseState<T extends InkResponse> extends State<T> with AutomaticKe
}
@override
void didUpdateWidget(T oldWidget) {
void didUpdateWidget(_InnerInkResponse oldWidget) {
super.didUpdateWidget(oldWidget);
if (_isWidgetEnabled(widget) != _isWidgetEnabled(oldWidget)) {
_handleHoverChange(_hovering);
......@@ -628,6 +769,9 @@ class _InkResponseState<T extends InkResponse> extends State<T> with AutomaticKe
updateKeepAlive();
}
if (type == _HighlightType.pressed) {
widget.parentState?.markChildInkResponsePressed(this, value);
}
if (value == (highlight != null && highlight.active))
return;
if (value) {
......@@ -737,6 +881,8 @@ class _InkResponseState<T extends InkResponse> extends State<T> with AutomaticKe
}
void _handleTapDown(TapDownDetails details) {
if (_anyChildInkResponsePressed)
return;
_startSplash(details: details);
if (widget.onTapDown != null) {
widget.onTapDown(details);
......@@ -813,10 +959,11 @@ class _InkResponseState<T extends InkResponse> extends State<T> with AutomaticKe
_highlights[highlight]?.dispose();
_highlights[highlight] = null;
}
widget.parentState?.markChildInkResponsePressed(this, false);
super.deactivate();
}
bool _isWidgetEnabled(InkResponse widget) {
bool _isWidgetEnabled(_InnerInkResponse widget) {
return widget.onTap != null || widget.onDoubleTap != null || widget.onLongPress != null;
}
......@@ -840,7 +987,9 @@ class _InkResponseState<T extends InkResponse> extends State<T> with AutomaticKe
}
_currentSplash?.color = widget.splashColor ?? Theme.of(context).splashColor;
final bool canRequestFocus = enabled && widget.canRequestFocus;
return Actions(
return _ParentInkResponseProvider(
state: this,
child: Actions(
actions: _actionMap,
child: Focus(
focusNode: widget.focusNode,
......@@ -862,6 +1011,7 @@ class _InkResponseState<T extends InkResponse> extends State<T> with AutomaticKe
),
),
),
),
);
}
}
......
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