Mobile Development 10 min read

Resolving Gesture Conflicts Between FlutterView and iOS Full‑Screen Back Gesture Using a ProxyGestureRecognizer

This article explains how to enable Flutter pages to receive touch events and coexist with an iOS full‑screen right‑swipe back gesture by introducing a custom ProxyGestureRecognizer that competes with native recognizers and maps Flutter's internal gesture state to UIKit.

Watermelon Video Tech Team
Watermelon Video Tech Team
Watermelon Video Tech Team
Resolving Gesture Conflicts Between FlutterView and iOS Full‑Screen Back Gesture Using a ProxyGestureRecognizer

Background : In mobile client development, gesture recognition is essential. Flutter provides a UIView subclass (FlutterView) that forwards all touch events through the UIView touch methods (touchesBegan/Moved/Cancelled/Ended) to Flutter's gesture system.

Problem : The Xigua video iOS client adds a PanGestureRecognizer to the UINavigationController view to implement a full‑screen right‑swipe back action. This recognizer consumes all touch events, preventing them from reaching FlutterView, which makes Flutter list scrolling impossible.

First Attempt : Setting the recognizer's cancelsTouchesInView property to NO allowed vertical scrolling but horizontal lists still triggered the back animation. The root cause is that iOS GestureRecognizer s have higher priority than UIView touch methods, and when both parent and child can handle a gesture, the parent should not block the child.

Continued Attempts : To give FlutterView an equal chance to compete for touch events, a custom ProxyGestureRecognizer is introduced. This agent receives iOS touch events, forwards them to FlutterView (with cancelsTouchesInView = NO), maps Flutter's internal gesture state to the recognizer's state, and then competes with other iOS recognizers.

ProxyGestureRecognizer State Logic :

- (void)flutterHandleTouch:(BOOL)isWorking {
    if (isWorking && self.state == UIGestureRecognizerStatePossible) {
        self.state = UIGestureRecognizerStateBegan;
        return;
    }
    if (!isWorking && self.state == UIGestureRecognizerStatePossible) {
        self.state = UIGestureRecognizerStateFailed;
        return;
    }
}

Obtaining FlutterView Internal Gesture State : A custom Flutter gesture recognizer extending PanGestureRecognizer is created. It overrides acceptGesture and rejectGesture to set a flag indicating whether Flutter is handling the touch, then notifies the iOS side via a platform channel.

class _PointerTracker extends PanGestureRecognizer {
  bool _flutterGestureIsWorking = false;

  @override
  void rejectGesture(int pointer) {
    super.rejectGesture(pointer);
    _flutterGestureIsWorking = true;
    _notify();
  }

  @override
  void acceptGesture(int pointer) {
    super.acceptGesture(pointer);
    _flutterGestureIsWorking = false;
    _notify();
  }

  void _notify() {
    GestureConflict.flutterGestureStateChanged(_flutterGestureIsWorking);
  }
}

This recognizer is wrapped in a FlutterGestureTracker widget that uses RawGestureDetector to place the custom recognizer at the root of the widget tree, ensuring it can compete with all other gestures.

class FlutterGestureTracker extends StatelessWidget {
  FlutterGestureTracker({Key key, this.child}) : super(key: key);
  final Widget child;

  @override
  Widget build(BuildContext context) {
    return RawGestureDetector(
      behavior: HitTestBehavior.translucent,
      gestures: {
        _PointerTracker: GestureRecognizerFactoryWithHandlers<_PointerTracker>(
          () => _PointerTracker(),
          (_PointerTracker instance) {
            // initializer if needed
          },
        ),
      },
      child: child,
    );
  }
}

Further Exploration : The proxy approach works for GestureRecognizer s but does not cover Flutter Listener s, which bypass the gesture arena. The article mentions possible AOP techniques using Dart's dill transform to instrument listeners, though this is still experimental.

Conclusion : Cross‑platform frameworks inevitably face native integration challenges. By using a proxy recognizer to map Flutter's gesture state to iOS recognizer states, developers can resolve gesture conflicts such as full‑screen back gestures interfering with Flutter list scrolling.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

FlutterMobile DevelopmentiOSGestureConflictGestureRecognizerProxyGestureRecognizer
Watermelon Video Tech Team
Written by

Watermelon Video Tech Team

Technical practice sharing from Watermelon Video

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.