WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

ScaleDetector doesn't work when a Component with DragCallbacks is added #2635

@ojciec-dev

Description

@ojciec-dev

Current bug behavior

ScaleDetector doesn't work when a Component with DragCallbacks is added.

Expected behavior

Scale gesture (pinch-to-zoom) should work regardless if a Component with DragCallbacks is registered. I'd expect to distinguish between two-finger scale gestures from one-finger tap and drag gestures.

In the example below you can drag the green rectangle but you cannot scale the board. When you remove DragCallbacks mixin, scale gesture starts working.

Steps to reproduce

  1. Use ScaleDetector with FlutterGame
  2. Add a child with DragCallbacks
  3. Notice onScaleUpdate is not being called after scale gesture
  4. Remove DragCallbacks mixin and notice onScaleUpdate is now being called
import 'package:flame/components.dart';
import 'package:flame/events.dart';
import 'package:flame/game.dart';
import 'package:flame/input.dart';
import 'package:flame/palette.dart';
import 'package:flutter/material.dart';

class ScaleDragGame extends StatelessWidget {
  const ScaleDragGame({super.key});

  @override
  Widget build(BuildContext context) {
    final game = ScaleDragFlameGame();

    return GameWidget(game: game);
  }
}

/// `onScale` methods are not called when a Component with DragCallbacks is added as a child.
/// Green rectangle can be dragged around but scale gestures don't work. But if I remove DragCallbacks from
/// [DraggableRectangle] scale gestures start to work.
class ScaleDragFlameGame extends FlameGame with ScaleDetector {
  late final CameraComponent cameraComponent;
  late double startZoom;

  ScaleDragFlameGame();

  @override
  Color backgroundColor() => Colors.yellow;

  @override
  Future<void> onLoad() async {
    final world = World();
    cameraComponent = CameraComponent(world: world)
      ..viewfinder.anchor = Anchor.center
      ..viewport.anchor = Anchor.center;
    addAll([world, cameraComponent]);

    world.add(DraggableRectangle(
      size: size / 4,
      position: size / 6,
      paint: BasicPalette.darkGreen.paint(),
    ));
  }

  @override
  void onScaleStart(ScaleStartInfo info) {
    startZoom = cameraComponent.viewfinder.zoom;
  }

  @override
  void onScaleUpdate(ScaleUpdateInfo info) {
    /// not called when Component with DragCallbacks was added

    final currentScale = info.scale.global;
    if (!currentScale.isIdentity()) {
      final newZoom = (startZoom * currentScale.y).clamp(1.0, 6.0);
      cameraComponent.viewfinder.zoom = newZoom;
    } else {
      final delta = info.delta.game;
      cameraComponent.viewfinder.position.translate(-delta.x, -delta.y);
    }
  }
}

/// Remove [DragCallbacks] and see that pinch-to-zoom gestures start working
class DraggableRectangle extends RectangleComponent with DragCallbacks {
  DraggableRectangle({
    super.position,
    super.size,
    super.paint,
  });

  @override
  void onDragUpdate(DragUpdateEvent event) {
    super.onDragUpdate(event);
    position += event.delta;
  }
}

Flutter doctor output

[✓] Flutter (Channel stable, 3.10.5, on macOS 13.2.1 22D68 darwin-arm64, locale en-US)
    • Flutter version 3.10.5 on channel stable at /Users/wojciechplesiak/Development/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 796c8ef792 (7 weeks ago), 2023-06-13 15:51:02 -0700
    • Engine revision 45f6e00911
    • Dart version 3.0.5
    • DevTools version 2.23.1

More environment information

  • Flame version: 1.8.1
  • Platform affected: android
  • Platform version affected: android 13

More information

I want to have draggable components placed on the zoomable board. Imagine you have a puzzle board and you want to zoom in to be able to drag the smaller pieces with precision. DragCallbacks is taking over all touch inputs even when they happen outside of the Component. I see under the hood that whenever a Component with DragCallbacks is added ImmediateMultiDragGestureRecognizer is registered as one of the gestureDetectors (here).

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions