@@ -174,6 +174,29 @@ abstract class InteractiveInkFeatureFactory {
174
174
});
175
175
}
176
176
177
+ abstract class _ParentInkResponseState {
178
+ void markChildInkResponsePressed (_ParentInkResponseState childState, bool value);
179
+ }
180
+
181
+ class _ParentInkResponseProvider extends InheritedWidget {
182
+ const _ParentInkResponseProvider ({
183
+ this .state,
184
+ Widget child,
185
+ }) : super (child: child);
186
+
187
+ final _ParentInkResponseState state;
188
+
189
+ @override
190
+ bool updateShouldNotify (_ParentInkResponseProvider oldWidget) => state != oldWidget.state;
191
+
192
+ static _ParentInkResponseState of (BuildContext context) {
193
+ return context.dependOnInheritedWidgetOfExactType <_ParentInkResponseProvider >()? .state;
194
+ }
195
+ }
196
+
197
+ typedef _GetRectCallback = RectCallback Function (RenderBox referenceBox);
198
+ typedef _CheckContext = bool Function (BuildContext context);
199
+
177
200
/// An area of a [Material] that responds to touch. Has a configurable shape and
178
201
/// can be configured to clip splashes that extend outside its bounds or not.
179
202
///
@@ -255,7 +278,7 @@ abstract class InteractiveInkFeatureFactory {
255
278
/// * [GestureDetector] , for listening for gestures without ink splashes.
256
279
/// * [RaisedButton] and [FlatButton] , two kinds of buttons in material design.
257
280
/// * [IconButton] , which combines [InkResponse] with an [Icon] .
258
- class InkResponse extends StatefulWidget {
281
+ class InkResponse extends StatelessWidget {
259
282
/// Creates an area of a [Material] that responds to touch.
260
283
///
261
284
/// Must have an ancestor [Material] widget in which to cause ink reactions.
@@ -508,6 +531,40 @@ class InkResponse extends StatefulWidget {
508
531
/// slightly more efficient).
509
532
RectCallback getRectCallback (RenderBox referenceBox) => null ;
510
533
534
+ @override
535
+ Widget build (BuildContext context) {
536
+ final _ParentInkResponseState parentState = _ParentInkResponseProvider .of (context);
537
+ return _InnerInkResponse (
538
+ child: child,
539
+ onTap: onTap,
540
+ onTapDown: onTapDown,
541
+ onTapCancel: onTapCancel,
542
+ onDoubleTap: onDoubleTap,
543
+ onLongPress: onLongPress,
544
+ onHighlightChanged: onHighlightChanged,
545
+ onHover: onHover,
546
+ containedInkWell: containedInkWell,
547
+ highlightShape: highlightShape,
548
+ radius: radius,
549
+ borderRadius: borderRadius,
550
+ customBorder: customBorder,
551
+ focusColor: focusColor,
552
+ hoverColor: hoverColor,
553
+ highlightColor: highlightColor,
554
+ splashColor: splashColor,
555
+ splashFactory: splashFactory,
556
+ enableFeedback: enableFeedback,
557
+ excludeFromSemantics: excludeFromSemantics,
558
+ focusNode: focusNode,
559
+ canRequestFocus: canRequestFocus,
560
+ onFocusChange: onFocusChange,
561
+ autofocus: autofocus,
562
+ parentState: parentState,
563
+ getRectCallback: getRectCallback,
564
+ debugCheckContext: debugCheckContext,
565
+ );
566
+ }
567
+
511
568
/// Asserts that the given context satisfies the prerequisites for
512
569
/// this class.
513
570
///
@@ -521,9 +578,74 @@ class InkResponse extends StatefulWidget {
521
578
assert (debugCheckHasDirectionality (context));
522
579
return true ;
523
580
}
581
+ }
582
+
583
+ class _InnerInkResponse extends StatefulWidget {
584
+ const _InnerInkResponse ({
585
+ this .child,
586
+ this .onTap,
587
+ this .onTapDown,
588
+ this .onTapCancel,
589
+ this .onDoubleTap,
590
+ this .onLongPress,
591
+ this .onHighlightChanged,
592
+ this .onHover,
593
+ this .containedInkWell = false ,
594
+ this .highlightShape = BoxShape .circle,
595
+ this .radius,
596
+ this .borderRadius,
597
+ this .customBorder,
598
+ this .focusColor,
599
+ this .hoverColor,
600
+ this .highlightColor,
601
+ this .splashColor,
602
+ this .splashFactory,
603
+ this .enableFeedback = true ,
604
+ this .excludeFromSemantics = false ,
605
+ this .focusNode,
606
+ this .canRequestFocus = true ,
607
+ this .onFocusChange,
608
+ this .autofocus = false ,
609
+ this .parentState,
610
+ this .getRectCallback,
611
+ this .debugCheckContext,
612
+ }) : assert (containedInkWell != null ),
613
+ assert (highlightShape != null ),
614
+ assert (enableFeedback != null ),
615
+ assert (excludeFromSemantics != null ),
616
+ assert (autofocus != null ),
617
+ assert (canRequestFocus != null );
618
+
619
+ final Widget child;
620
+ final GestureTapCallback onTap;
621
+ final GestureTapDownCallback onTapDown;
622
+ final GestureTapCallback onTapCancel;
623
+ final GestureTapCallback onDoubleTap;
624
+ final GestureLongPressCallback onLongPress;
625
+ final ValueChanged <bool > onHighlightChanged;
626
+ final ValueChanged <bool > onHover;
627
+ final bool containedInkWell;
628
+ final BoxShape highlightShape;
629
+ final double radius;
630
+ final BorderRadius borderRadius;
631
+ final ShapeBorder customBorder;
632
+ final Color focusColor;
633
+ final Color hoverColor;
634
+ final Color highlightColor;
635
+ final Color splashColor;
636
+ final InteractiveInkFeatureFactory splashFactory;
637
+ final bool enableFeedback;
638
+ final bool excludeFromSemantics;
639
+ final ValueChanged <bool > onFocusChange;
640
+ final bool autofocus;
641
+ final FocusNode focusNode;
642
+ final bool canRequestFocus;
643
+ final _ParentInkResponseState parentState;
644
+ final _GetRectCallback getRectCallback;
645
+ final _CheckContext debugCheckContext;
524
646
525
647
@override
526
- _InkResponseState < InkResponse > createState () => _InkResponseState < InkResponse > ();
648
+ _InkResponseState createState () => _InkResponseState ();
527
649
528
650
@override
529
651
void debugFillProperties (DiagnosticPropertiesBuilder properties) {
@@ -554,7 +676,9 @@ enum _HighlightType {
554
676
focus,
555
677
}
556
678
557
- class _InkResponseState <T extends InkResponse > extends State <T > with AutomaticKeepAliveClientMixin <T > {
679
+ class _InkResponseState extends State <_InnerInkResponse >
680
+ with AutomaticKeepAliveClientMixin <_InnerInkResponse >
681
+ implements _ParentInkResponseState {
558
682
Set <InteractiveInkFeature > _splashes;
559
683
InteractiveInkFeature _currentSplash;
560
684
bool _hovering = false ;
@@ -563,6 +687,23 @@ class _InkResponseState<T extends InkResponse> extends State<T> with AutomaticKe
563
687
564
688
bool get highlightsExist => _highlights.values.where ((InkHighlight highlight) => highlight != null ).isNotEmpty;
565
689
690
+ final ObserverList <_ParentInkResponseState > _activeChildren = ObserverList <_ParentInkResponseState >();
691
+ @override
692
+ void markChildInkResponsePressed (_ParentInkResponseState childState, bool value) {
693
+ assert (childState != null );
694
+ final bool lastAnyPressed = _anyChildInkResponsePressed;
695
+ if (value) {
696
+ _activeChildren.add (childState);
697
+ } else {
698
+ _activeChildren.remove (childState);
699
+ }
700
+ final bool nowAnyPressed = _anyChildInkResponsePressed;
701
+ if (nowAnyPressed != lastAnyPressed) {
702
+ widget.parentState? .markChildInkResponsePressed (this , nowAnyPressed);
703
+ }
704
+ }
705
+ bool get _anyChildInkResponsePressed => _activeChildren.isNotEmpty;
706
+
566
707
void _handleAction (ActivateIntent intent) {
567
708
_startSplash (context: context);
568
709
_handleTap (context);
@@ -578,7 +719,7 @@ class _InkResponseState<T extends InkResponse> extends State<T> with AutomaticKe
578
719
}
579
720
580
721
@override
581
- void didUpdateWidget (T oldWidget) {
722
+ void didUpdateWidget (_InnerInkResponse oldWidget) {
582
723
super .didUpdateWidget (oldWidget);
583
724
if (_isWidgetEnabled (widget) != _isWidgetEnabled (oldWidget)) {
584
725
_handleHoverChange (_hovering);
@@ -628,6 +769,9 @@ class _InkResponseState<T extends InkResponse> extends State<T> with AutomaticKe
628
769
updateKeepAlive ();
629
770
}
630
771
772
+ if (type == _HighlightType .pressed) {
773
+ widget.parentState? .markChildInkResponsePressed (this , value);
774
+ }
631
775
if (value == (highlight != null && highlight.active))
632
776
return ;
633
777
if (value) {
@@ -737,6 +881,8 @@ class _InkResponseState<T extends InkResponse> extends State<T> with AutomaticKe
737
881
}
738
882
739
883
void _handleTapDown (TapDownDetails details) {
884
+ if (_anyChildInkResponsePressed)
885
+ return ;
740
886
_startSplash (details: details);
741
887
if (widget.onTapDown != null ) {
742
888
widget.onTapDown (details);
@@ -813,10 +959,11 @@ class _InkResponseState<T extends InkResponse> extends State<T> with AutomaticKe
813
959
_highlights[highlight]? .dispose ();
814
960
_highlights[highlight] = null ;
815
961
}
962
+ widget.parentState? .markChildInkResponsePressed (this , false );
816
963
super .deactivate ();
817
964
}
818
965
819
- bool _isWidgetEnabled (InkResponse widget) {
966
+ bool _isWidgetEnabled (_InnerInkResponse widget) {
820
967
return widget.onTap != null || widget.onDoubleTap != null || widget.onLongPress != null ;
821
968
}
822
969
@@ -840,25 +987,28 @@ class _InkResponseState<T extends InkResponse> extends State<T> with AutomaticKe
840
987
}
841
988
_currentSplash? .color = widget.splashColor ?? Theme .of (context).splashColor;
842
989
final bool canRequestFocus = enabled && widget.canRequestFocus;
843
- return Actions (
844
- actions: _actionMap,
845
- child: Focus (
846
- focusNode: widget.focusNode,
847
- canRequestFocus: canRequestFocus,
848
- onFocusChange: _handleFocusUpdate,
849
- autofocus: widget.autofocus,
850
- child: MouseRegion (
851
- onEnter: enabled ? _handleMouseEnter : null ,
852
- onExit: enabled ? _handleMouseExit : null ,
853
- child: GestureDetector (
854
- onTapDown: enabled ? _handleTapDown : null ,
855
- onTap: enabled ? () => _handleTap (context) : null ,
856
- onTapCancel: enabled ? _handleTapCancel : null ,
857
- onDoubleTap: widget.onDoubleTap != null ? _handleDoubleTap : null ,
858
- onLongPress: widget.onLongPress != null ? () => _handleLongPress (context) : null ,
859
- behavior: HitTestBehavior .opaque,
860
- excludeFromSemantics: widget.excludeFromSemantics,
861
- child: widget.child,
990
+ return _ParentInkResponseProvider (
991
+ state: this ,
992
+ child: Actions (
993
+ actions: _actionMap,
994
+ child: Focus (
995
+ focusNode: widget.focusNode,
996
+ canRequestFocus: canRequestFocus,
997
+ onFocusChange: _handleFocusUpdate,
998
+ autofocus: widget.autofocus,
999
+ child: MouseRegion (
1000
+ onEnter: enabled ? _handleMouseEnter : null ,
1001
+ onExit: enabled ? _handleMouseExit : null ,
1002
+ child: GestureDetector (
1003
+ onTapDown: enabled ? _handleTapDown : null ,
1004
+ onTap: enabled ? () => _handleTap (context) : null ,
1005
+ onTapCancel: enabled ? _handleTapCancel : null ,
1006
+ onDoubleTap: widget.onDoubleTap != null ? _handleDoubleTap : null ,
1007
+ onLongPress: widget.onLongPress != null ? () => _handleLongPress (context) : null ,
1008
+ behavior: HitTestBehavior .opaque,
1009
+ excludeFromSemantics: widget.excludeFromSemantics,
1010
+ child: widget.child,
1011
+ ),
862
1012
),
863
1013
),
864
1014
),
0 commit comments