# pointer_interceptor

|             | iOS     | Web |
|-------------|---------|-----|
| **Support** | iOS 13+ | Any |

`PointerInterceptor` is a widget that prevents mouse events from being captured by an underlying [`HtmlElementView`](https://api.flutter.dev/flutter/widgets/HtmlElementView-class.html) in web, or an underlying [`PlatformView`](https://api.flutter.dev/flutter/widgets/PlatformViewLink-class.html) on iOS.

Using multiple `PointerInterceptor` instances on iOS can be slow and increases memory usage due to the performance overhead of the underlying platform view.

## What is the problem?

When overlaying Flutter widgets on top of `HtmlElementView`/`PlatformView` widgets that respond to mouse gestures (handle clicks, for example), the clicks will be consumed by the `HtmlElementView`/`PlatformView`, and not relayed to Flutter.

The result is that Flutter widget's `onTap` (and other) handlers won't fire as expected, but they'll affect the underlying native platform view.

|The problem...|
|:-:|
|![Depiction of problematic areas](https://raw.githubusercontent.com/flutter/packages/cb6dbcdd230528c0c246c81d93386c512f9a23d0/packages/pointer_interceptor/pointer_interceptor/doc/img/affected-areas.png)|
|_In the dashed areas, mouse events won't work as expected. The `HtmlElementView` will consume them before Flutter sees them._|

## How does this work?

In web, `PointerInterceptor` creates a platform view consisting of an empty HTML element, while on iOS it creates an empty `UIView` instead. The element has the size of its `child` widget, and is inserted in the layer tree _behind_ its child in paint order.

This empty platform view doesn't do anything with mouse events, other than preventing them from reaching other platform views underneath it.

This gives an opportunity to the Flutter framework to handle the click, as expected:

|The solution...|
|:-:|
|![Depiction of the solution](https://raw.githubusercontent.com/flutter/packages/cb6dbcdd230528c0c246c81d93386c512f9a23d0/packages/pointer_interceptor/pointer_interceptor/doc/img/fixed-areas.png)|
|_Each `PointerInterceptor` (green) renders between Flutter widgets and the underlying `HtmlElementView`. Mouse events now can't reach the background HtmlElementView, and work as expected._|

## How to use

Some common scenarios where this widget may come in handy:

* [FAB](https://api.flutter.dev/flutter/material/FloatingActionButton-class.html) unclickable in an app that renders a full-screen background Map
* Custom Play/Pause buttons on top of a video element don't work
* Drawer contents not interactive when it overlaps an iframe element
* ...

All the cases above have in common that they attempt to render Flutter widgets *on top* of platform views that handle pointer events.

There's two ways that the `PointerInterceptor` widget can be used to solve the problems above:

1. Wrapping your button element directly (FAB, Custom Play/Pause button...):

    ```dart
    PointerInterceptor(
      child: ElevatedButton(...),
    )
    ```

2. As a root container for a "layout" element, wrapping a bunch of other elements (like a Drawer):

    ```dart
    Scaffold(
      ...
      drawer: PointerInterceptor(
        child: Drawer(
          child: ...
        ),
      ),
      ...
    )
    ```

### `intercepting`

A common use of the `PointerInterceptor` widget is to block clicks only under
certain conditions (`isVideoShowing`, `isPanelOpen`...).

The `intercepting` property allows the `PointerInterceptor` widget to render
itself (or not) depending on a boolean value, instead of having to manually
write an `if/else` on the Flutter App widget tree, so code like this:

  ```dart
  if (someCondition) {
    return PointerInterceptor(
      child: ElevatedButton(...),
    )
  } else {
    return ElevatedButton(...),
  }
  ```

can be rewritten as:

   ```dart
    return PointerInterceptor(
      intercepting: someCondition,
      child: ElevatedButton(...),
    )
   ```

Note: when `intercepting` is false, the `PointerInterceptor` will not render
_anything_ in flutter, and just return its `child`. The code is exactly
equivalent to the example above.

### `debug`

The `PointerInterceptor` widget has a `debug` property, that will render it visibly on the screen (similar to the images above).

This may be useful to see what the widget is actually covering when used as a layout element.
