Skip to content

Commit

Permalink
feat: add isTouchScrollEnabled
Browse files Browse the repository at this point in the history
Resolves #436, and
- https://rive.app/community/forums/support/fsnLLkXUaA62/flutter-scrolling-not-working-as-expected-on-mobile/ft3UcorwBVAf

Our web runtime has a `isTouchScrollEnabled`. This reproduces that behaviour.

```
  /// For Rive Listeners, allows scrolling behavior to still occur on Rive
  /// widgets when a touch/drag action is performed on touch-enabled devices.
  /// Otherwise, scroll behavior may be prevented on touch/drag actions on the
  /// widget by default.
  ///
  /// Default `false`.
```

I made some TODOs in the code for future considerations. We might want to opt in to give users more control over which gestures should be registered, and we can potentially be smart about doing this conditionally, depending on what the Rive graphic allows you to do. But this requires more investigation.

https://github.com/user-attachments/assets/81119bed-cb8a-4672-9559-d1c85832bad9

Diffs=
8d1fdd16ad feat: add isTouchScrollEnabled (#8651)

Co-authored-by: Gordon <pggordonhayes@gmail.com>
  • Loading branch information
HayesGordon and HayesGordon committed Nov 27, 2024
1 parent 1848316 commit 16d549f
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 13 deletions.
2 changes: 1 addition & 1 deletion .rive_head
Original file line number Diff line number Diff line change
@@ -1 +1 @@
7986d64d8371531716ea3f038dcbec5da187e6cd
8d1fdd16ad196c3acca18faa89db2e1f4ef94365
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## Upcoming

- Adds the `isTouchScrollEnabled` property to `RiveAnimation` and `Rive` widgets. When `true` allows scrolling behavior to occur on Rive widgets when a touch/drag action is performed on touch-enabled devices. Defauls to `false`, which means Rive will "absorb" the pointer down event and a scroll cannot be triggered if the touch occured within a Rive Listener area. Setting to `true` will impact Rive's capability to handle multiple gestures simultaneously.

## 0.13.18

- Bump to latest `rive_common`, v0.4.13. Resolves [issues building rive_common downstream](https://github.com/rive-app/rive-flutter/issues/354#issuecomment-2491004291).
Expand Down
44 changes: 37 additions & 7 deletions lib/src/rive.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:rive/src/controllers/state_machine_controller.dart';
import 'package:rive/src/rive_core/artboard.dart';
import 'package:rive/src/rive_core/state_machine_controller.dart'
show HitResult;
import 'package:rive/src/rive_render_box.dart';
import 'package:rive/src/runtime_artboard.dart';
import 'package:rive_common/math.dart';
Expand Down Expand Up @@ -99,6 +101,14 @@ class Rive extends LeafRenderObjectWidget {
/// Default `1.0`.
final double speedMultiplier;

/// For Rive Listeners, allows scrolling behavior to still occur on Rive
/// widgets when a touch/drag action is performed on touch-enabled devices.
/// Otherwise, scroll behavior may be prevented on touch/drag actions on the
/// widget by default.
///
/// Default `false`.
final bool isTouchScrollEnabled;

const Rive({
required this.artboard,
super.key,
Expand All @@ -111,6 +121,7 @@ class Rive extends LeafRenderObjectWidget {
this.alignment = Alignment.center,
this.clipRect,
this.speedMultiplier = 1.0,
this.isTouchScrollEnabled = false,
});

@override
Expand All @@ -128,7 +139,8 @@ class Rive extends LeafRenderObjectWidget {
..enableHitTests = enablePointerEvents
..cursor = cursor
..behavior = behavior
..speedMultiplier = speedMultiplier;
..speedMultiplier = speedMultiplier
..isTouchScrollEnabled = isTouchScrollEnabled;
}

@override
Expand All @@ -147,7 +159,8 @@ class Rive extends LeafRenderObjectWidget {
..enableHitTests = enablePointerEvents
..cursor = cursor
..behavior = behavior
..speedMultiplier = speedMultiplier;
..speedMultiplier = speedMultiplier
..isTouchScrollEnabled = isTouchScrollEnabled;
}
}

Expand Down Expand Up @@ -245,18 +258,34 @@ class RiveRenderObject extends RiveRenderBox implements MouseTrackerAnnotation {
return false;
}

// TODO: A possible alternative to [isTouchScrollEnabled] is to allow
// users to set custom recognizers. Or for us to provide
// heuristics on whether a Rive graphic has certain gestures:
// - Pointer down/up
// - Drag
// - Scroll
// - etc.
// With this information we can better decide which recognizers to use,
// while optionally allowing end users to override it, or provide custom ones.
// Can be considered for `rive_native`.
//
// https://api.flutter.dev/flutter/gestures/GestureArenaManager-class.html
final _recognizer = ImmediateMultiDragGestureRecognizer();

@override
void handleEvent(PointerEvent event, HitTestEntry entry) {
assert(debugHandleEvent(event, entry));
if (!enableHitTests || !attached) {
return;
}
if (event is PointerDownEvent) {
_hitHelper(
event,
(controller, artboardPosition) =>
controller.pointerDown(artboardPosition, event),
);
_hitHelper(event, (controller, artboardPosition) {
final hitResult = controller.pointerDown(artboardPosition, event);

if (hitResult != HitResult.none && !isTouchScrollEnabled) {
_recognizer.addPointer(event);
}
});
}
if (event is PointerUpEvent) {
_hitHelper(
Expand Down Expand Up @@ -338,6 +367,7 @@ class RiveRenderObject extends RiveRenderBox implements MouseTrackerAnnotation {
@override
void dispose() {
_artboard.redraw.removeListener(scheduleRepaint);
_recognizer.dispose();
super.dispose();
}

Expand Down
5 changes: 0 additions & 5 deletions lib/src/rive_core/state_machine_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -466,8 +466,6 @@ class StateMachineController extends RiveAnimationController<CoreContext>

late CoreContext core;

final _recognizer = ImmediateMultiDragGestureRecognizer();

@override
bool init(CoreContext core) {
this.core = core;
Expand Down Expand Up @@ -734,9 +732,6 @@ class StateMachineController extends RiveAnimationController<CoreContext>
hitEvent: ListenerType.down,
pointerEvent: event,
);
if (hitResult != HitResult.none) {
_recognizer.addPointer(event);
}
return hitResult;
}

Expand Down
9 changes: 9 additions & 0 deletions lib/src/rive_render_box.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ abstract class RiveRenderBox extends RenderBox {
Rect? _clipRect;
bool _tickerModeEnabled = true;
bool _enableHitTests = false;
bool _isTouchScrollEnabled = false;

bool get useArtboardSize => _useArtboardSize;

Expand Down Expand Up @@ -89,6 +90,14 @@ abstract class RiveRenderBox extends RenderBox {
}
}

bool get isTouchScrollEnabled => _isTouchScrollEnabled;

set isTouchScrollEnabled(bool value) {
if (value != _isTouchScrollEnabled) {
_isTouchScrollEnabled = value;
}
}

bool _paintedLastFrame = false;

@override
Expand Down
13 changes: 13 additions & 0 deletions lib/src/widgets/rive_animation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,14 @@ class RiveAnimation extends StatefulWidget {
/// Default `1.0`.
final double speedMultiplier;

/// For Rive Listeners, allows scrolling behavior to still occur on Rive
/// widgets when a touch/drag action is performed on touch-enabled devices.
/// Otherwise, scroll behavior may be prevented on touch/drag actions on the
/// widget by default.
///
/// Default `false`.
final bool isTouchScrollEnabled;

/// Creates a new [RiveAnimation] from an asset bundle.
///
/// *Example:*
Expand All @@ -98,6 +106,7 @@ class RiveAnimation extends StatefulWidget {
this.behavior = RiveHitTestBehavior.opaque,
this.objectGenerator,
this.speedMultiplier = 1,
this.isTouchScrollEnabled = false,
Key? key,
}) : name = asset,
file = null,
Expand Down Expand Up @@ -128,6 +137,7 @@ class RiveAnimation extends StatefulWidget {
this.behavior = RiveHitTestBehavior.opaque,
this.objectGenerator,
this.speedMultiplier = 1,
this.isTouchScrollEnabled = false,
Key? key,
}) : name = url,
file = null,
Expand Down Expand Up @@ -156,6 +166,7 @@ class RiveAnimation extends StatefulWidget {
this.behavior = RiveHitTestBehavior.opaque,
this.objectGenerator,
this.speedMultiplier = 1,
this.isTouchScrollEnabled = false,
Key? key,
}) : name = path,
file = null,
Expand Down Expand Up @@ -185,6 +196,7 @@ class RiveAnimation extends StatefulWidget {
this.controllers = const [],
this.onInit,
this.speedMultiplier = 1,
this.isTouchScrollEnabled = false,
Key? key,
this.behavior = RiveHitTestBehavior.opaque,
}) : name = null,
Expand Down Expand Up @@ -356,6 +368,7 @@ class RiveAnimationState extends State<RiveAnimation> {
enablePointerEvents: _shouldAddHitTesting,
behavior: widget.behavior,
speedMultiplier: widget.speedMultiplier,
isTouchScrollEnabled: widget.isTouchScrollEnabled,
)
: widget.placeHolder ?? const SizedBox();
}

0 comments on commit 16d549f

Please sign in to comment.