Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add hitSlop prop on iOS and Android #5720

Closed
wants to merge 1 commit into from

Conversation

jesseruder
Copy link
Contributor

New prop hitSlop allows extending the touch area of Touchable components. This makes it easier to touch small buttons without needing to change your styles.

It takes top, bottom, left, and right same as the pressRetentionOffset prop. When a touch is moved, hitSlop is combined with pressRetentionOffset to determine how far the touch can move off the button before deactivating the button.

On Android I had to add a new file ids.xml to generate a unique ID to use for the tag where I store the hitSlop state. The iOS side is more straightforward.

@terribleben worked on the iOS and JS parts of this diff.

Fixes #110

@facebook-github-bot
Copy link
Contributor

By analyzing the blame information on this pull request, we identified @dmmiller, @andreicoman11 and @Ehesp to be potential reviewers.

@facebook-github-bot facebook-github-bot added GH Review: review-needed CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. labels Feb 3, 2016
@@ -108,6 +113,10 @@ var TouchableBounce = React.createClass({
return this.props.pressRetentionOffset || PRESS_RETENTION_OFFSET;
},

touchableGetHitSlop: function(): number {

Choose a reason for hiding this comment

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

undefined This type is incompatible with number

@facebook-github-bot
Copy link
Contributor

@jesseruder updated the pull request.

@jesseruder
Copy link
Contributor Author

It looks like the tests don't like me doing import com.facebook.react.R in TouchTargetHelper. I'm not sure how to avoid this since you need to use a resource file Id or else you get an IllegalArgumentException. See http://stackoverflow.com/questions/2859574/the-key-must-be-an-application-specific-resource-id

@ide
Copy link
Contributor

ide commented Feb 3, 2016

@andreicoman11 @kmagiera are you guys the best people to look at Android touch system diffs?

@ide ide added Platform: iOS iOS applications. Android and removed GH Review: review-needed labels Feb 3, 2016
@ide
Copy link
Contributor

ide commented Feb 3, 2016

@bestander it looks like R.java isn't generated (?) because the tests don't use Gradle -- off the top of your head do you know how to make Buck take care of this for us?

@@ -118,6 +123,10 @@ var TouchableWithoutFeedback = React.createClass({
return this.props.pressRetentionOffset || PRESS_RETENTION_OFFSET;
},

Choose a reason for hiding this comment

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

undefined This type is incompatible with object type

@facebook-github-bot
Copy link
Contributor

@jesseruder updated the pull request.

hitSlopPixels.put("bottom", PixelUtil.toPixelFromDIP(hitSlop.getDouble("bottom")));
hitSlopPixels.put("left", PixelUtil.toPixelFromDIP(hitSlop.getDouble("left")));
hitSlopPixels.put("right", PixelUtil.toPixelFromDIP(hitSlop.getDouble("right")));
view.setTag(R.id.hitSlopTag, hitSlopPixels);
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not just add an extra property to the ReactViewGroup and assing it there? Calling setTag this way will often allocate an extra SparseArray.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Makes sense. I'll change that.

@facebook-github-bot
Copy link
Contributor

@jesseruder updated the pull request.

@jesseruder
Copy link
Contributor Author

I tried adding react_native_target('java/com/facebook/react/views/view:view') to ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK but that gave me:

BUILD FAILED: Cycle found: //ReactAndroid/src/main/java/com/facebook/react/uimanager:uimanager -> //ReactAndroid/src/main/java/com/facebook/react/views/view:view -> //ReactAndroid/src/main/java/com/facebook/react/uimanager:uimanager

Is there any clean way to solve this @bestander? I could add an interface under react/uimanager but that seems like overkill.

if ((localX >= 0 && localX < (child.getRight() - child.getLeft()))
&& (localY >= 0 && localY < (child.getBottom() - child.getTop()))) {
Rect hitSlopRect = new Rect();
if (child instanceof ReactViewGroup && ((ReactViewGroup) child).getHitSlopRect() != null) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you extract getHitSlopRect to an interface so that other views (such as Text elements) can implement hitSlop too if we need it?

@bestander
Copy link
Contributor

@jesseruder yeah, that sucks.
Looks like uimanager is quite large but I don't see a quick and clean way to split it.
Possible ways to fix: move TouchTargetHelper.java to view package or into its own package.

@mkonicek @foghina what do you think?

@skevy
Copy link
Contributor

skevy commented Feb 10, 2016

@mkonicek iOS side looks 👍 to me. LGTM

@skevy
Copy link
Contributor

skevy commented Feb 10, 2016

Also, just FYI martin, we've been using this internally and it's working great on both platforms :)

@mkonicek
Copy link
Contributor

Oh cool, good to know!

/**
* This defines how far your touch can start away from the button. This is
* added to `pressRetentionOffset` when moving off of the button.
* The touch area never extends past the parent view bounds and the Z-index
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be more obvious to the reader, something like ** NOTE ** or even "Experimental" would help here

@facebook-github-bot
Copy link
Contributor

@jesseruder updated the pull request.

@@ -202,6 +203,14 @@ const View = React.createClass({
onMoveShouldSetResponderCapture: PropTypes.func,

/**
* This defines how far a touch event can start away from the view.
* The touch area never extends past the parent view bounds and the Z-index
Copy link
Contributor

Choose a reason for hiding this comment

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

same as above

@facebook-github-bot
Copy link
Contributor

@jesseruder updated the pull request.

* This defines how far a touch event can start away from the view.
* The touch area never extends past the parent view bounds and the Z-index
* of sibling views always takes precedence if a touch hits two overlapping
* views.
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add a short example here showing how I would extend the area by n pixels in each direction? What's a reasonable number?

@facebook-github-bot
Copy link
Contributor

@jesseruder updated the pull request.

@mkonicek
Copy link
Contributor

Looks good! Just two small nits and would be nice to add a small example: https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/TouchableExample.js

@facebook-github-bot
Copy link
Contributor

@jesseruder updated the pull request.

@jesseruder
Copy link
Contributor Author

@mkonicek @andreicoman11 Added an example and more comments. Thanks!

@facebook-github-bot
Copy link
Contributor

@jesseruder updated the pull request.

1 similar comment
@facebook-github-bot
Copy link
Contributor

@jesseruder updated the pull request.

@facebook-github-bot
Copy link
Contributor

@jesseruder updated the pull request.

@facebook-github-bot
Copy link
Contributor

@jesseruder updated the pull request.

@ide
Copy link
Contributor

ide commented Feb 16, 2016

The example looks good and this is working on both platforms.

@ide
Copy link
Contributor

ide commented Feb 16, 2016

@facebook-github-bot shipit

@facebook-github-bot
Copy link
Contributor

Thanks for importing. If you are an FB employee go to https://our.intern.facebook.com/intern/opensource/github/pull_request/1041390565903389/int_phab to review.

@ghost ghost closed this in 0176ac4 Feb 17, 2016
@ide ide deleted the feature/hit_slop branch March 11, 2016 08:41
pglotov pushed a commit to pglotov/react-native that referenced this pull request Mar 15, 2016
Summary:New prop `hitSlop` allows extending the touch area of Touchable components. This makes it easier to touch small buttons without needing to change your styles.

It takes `top`, `bottom`, `left`, and `right` same as the `pressRetentionOffset` prop. When a touch is moved, `hitSlop` is combined with `pressRetentionOffset` to determine how far the touch can move off the button before deactivating the button.

On Android I had to add a new file `ids.xml` to generate a unique ID to use for the tag where I store the `hitSlop` state. The iOS side is more straightforward.

terribleben worked on the iOS and JS parts of this diff.

Fixes facebook#110
Closes facebook#5720

Differential Revision: D2941671

Pulled By: androidtrunkagent

fb-gh-sync-id: 07e3eb8b6a36eebf76968fdaac3c6ac335603194
shipit-source-id: 07e3eb8b6a36eebf76968fdaac3c6ac335603194
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Platform: iOS iOS applications.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants