Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[pointer_interceptor] Allow conditional pointer interception#538

Merged
fluttergithubbot merged 6 commits intoflutter:mainfrom
Rexios80:feature/pointer-interceptor-toggle
Feb 1, 2022
Merged

[pointer_interceptor] Allow conditional pointer interception#538
fluttergithubbot merged 6 commits intoflutter:mainfrom
Rexios80:feature/pointer-interceptor-toggle

Conversation

@Rexios80
Copy link
Member

Allow conditional pointer interception similar to AbsorbPointer and IgnorePointer

Fixes flutter/flutter#95363

Pre-launch Checklist

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I read and followed the relevant style guides and ran the auto-formatter. (Unlike the flutter/flutter repo, the flutter/packages repo does use dart format.)
  • I signed the CLA.
  • The title of the PR starts with the name of the package surrounded by square brackets, e.g. [shared_preferences]
  • I listed at least one issue that this PR fixes in the description above.
  • I updated pubspec.yaml with an appropriate new version according to the pub versioning philosophy, or this PR is exempt from version changes.
  • I updated CHANGELOG.md to add a description of the change, following repository CHANGELOG style.
  • I updated/added relevant documentation (doc comments with ///).
  • I added new tests to check the change I am making, or this PR is test-exempt.
  • All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@Rexios80

This comment has been minimized.

@override
Widget build(BuildContext context) {
if (!intercepting) {
return child;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't at all how the other classes you referenced behave. What's the use case for having a property vs. clients just not using the wrapper if this is the behavior they want?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm using floating_material_search_bar which always has a widget filling the whole screen for hit testing. I need the widget to pass through touches to a Google Map when the search bar is not focused, but intercept them when the search bar is focused.

I didn't look at the implementation of Ignore/AbsorbPointer, but how is this different than how they behave?

AbsorbPointer documentation:

When [absorbing] is true, this widget prevents its subtree from receiving pointer events by terminating hit testing at itself.

IgnorePointer documentation:

When [ignoring] is true, this widget (and its subtree) is invisible to hit testing.

PointerInterceptor(
  intercepting: intercepting,
  child: const Text(''),
);

Is a lot simpler than:

Builder(
  builder: (context) {
    if (intercepting) {
      return const PointerInterceptor(
        child: Text(''),
      );
    } else {
      return const Text('');
    }
  },
);

I used mobile.dart as reference for what to do when the flag is false.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't look at the implementation of Ignore/AbsorbPointer, but how is this different than how they behave?

They don't conditionally change what build returns, unless I missed something.

[...]
Is a lot simpler than:
[...]

That's true, but that's a false choice because you're duplicating the code to create the child. If what you want is to conditionally wrap something in a PointerInterceptor you could make a trivial local helper method that does that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On implementation

There's two ways to do this. One is what this PR does or the helper method that @stuartmorgan is suggecting (let's call it "conditional build"). Another one is to do it at the RenderObject level (let's call it "conditional render"). There are pros and cons.

Pros of conditional build:

  • If the value of intercepting doesn't change over time (or changes rarely), then it's more efficient for the false case because it doesn't increase the size of the Element tree.
  • Simple implementation (as this PR shows)

Pros of conditional render:

  • More efficient if the value of intercepting changes frequently. Because pointer interceptor is a platform view it alwaysNeedsCompositing, so it will break up pictures into more layers than when there's no interceptor. If the widget flips between intercepting and not, it will significantly alter the shape of the render tree and especially of the layer tree. At the render object level the tree could be kept more stable between intercepting or not because it could keep the same layer structure.

Conditional rendering would have to be implemented in this package. Conditional build can be implemented as a helper function.

On ergonomics

I really prefer the ergonomics of a flag compared to having to write a helper function. You won't have many interceptors in the same library, but you may have many interceptors across your codebase and the discovery of a custom helper function like this will be low. In most cases we want people to just be able to import this package and get good ergonomics from it out of the box. If enabling/disabling the interceptor is an important use-case, then I'd argue it should also be ergonomic out of the box. Honestly, I wouldn't want to write that if/else even once. If the interceptor is in the middle of a deep widget hierarchy, making it conditional will mess up all of the surrounding code.

@stuartmorgan-g stuartmorgan-g requested a review from ditman January 5, 2022 20:26
@ditman
Copy link
Member

ditman commented Jan 7, 2022

Thanks for the contribution @Rexios80! IMO this change makes the syntax for this case nicer to read than conditionally wrapping the children in the component.

My biggest concern with this is that it "looks like" it's more efficient than rendering/not rendering the PlatformInterceptor widget (because the Widget Tree doesn't change, yadda, yadda...), but in reality there's no performance benefit in keeping a non-intercepting PlatformInterceptor in the widget tree when the actual DOM is rendered (because the render method is returning a different set of children anyways!)

Let me discuss this with the web team; we've held up other changes to pointer interceptor, so we end up fixing the underlying issue that it solves (and not just alleviate its symptoms!)

@ditman
Copy link
Member

ditman commented Jan 11, 2022

Discussed this with @yjbanov and this looks like a change we want (plus an internal team might need to do something similar to this!)

@stuartmorgan-g
Copy link
Collaborator

@ditman Are there design issues to resolve still, or is this ready for you to review?

@ditman
Copy link
Member

ditman commented Jan 31, 2022

@ditman Are there design issues to resolve still, or is this ready for you to review?

@stuartmorgan this is ready to review and potentially merge, I'll get it done today.

Copy link
Member

@ditman ditman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs an update to the README.md to update the instructions with this new feature, I'll add a paragraph about this new convenience!

Copy link
Member

@ditman ditman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's go!

@yjbanov
Copy link
Contributor

yjbanov commented Jan 31, 2022

Added some points in #538 (comment), but LGTM overall.

@ditman ditman self-assigned this Feb 1, 2022
@fluttergithubbot fluttergithubbot merged commit 1377eed into flutter:main Feb 1, 2022
@ditman
Copy link
Member

ditman commented Feb 1, 2022

This has landed to main, and will be published to pub soon.

Again, thanks for the contribution @Rexios80! Keep them coming!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[pointer_interceptor] Allow conditional pointer interception

5 participants