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

Adds the ability to use UIManager to check if a node is an ancestor #7876

Closed
wants to merge 1 commit into from

Conversation

alvaromb
Copy link
Contributor

@alvaromb alvaromb commented Jun 1, 2016

Motivation

Sometimes is handy to check if a React node is a descendant of another node or not. For instance, I want to check if the focused TextInput is descendant of an specific ScrollView:

const currentlyFocusedField = TextInput.State.currentlyFocusedField()
UIManager.viewIsAncestorOf(
  currentlyFocusedField,
  this.getInnerViewNode(),
  (isAncestor) => {
    if (isAncestor) {
      console.log('The focused field is a descendant of this ScrollView!')
    }
  }
)

This function uses the same strategy as the measureLayout method to check if one node is an ancestor of other node. As the measureLayout method, this is performed outside the main thread.

By now I've only implemented the iOS version and its tests, but if this function is going to be merged I'll implement the Android version too. I have objc experience but no Java or Android, so I prefer to validate this functionality before jumping into developing the Android part.

@ghost
Copy link

ghost commented Jun 1, 2016

By analyzing the blame information on this pull request, we identified @alloy and @rigdern to be potential reviewers.

@ghost ghost 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 Jun 1, 2016
@ghost
Copy link

ghost commented Jun 1, 2016

@alvaromb updated the pull request.

@alvaromb
Copy link
Contributor Author

alvaromb commented Jun 2, 2016

Probably I should change the name of the function from viewIsAncestorOf to viewIsDescendantOf, it's more correct.

@alloy
Copy link
Contributor

alloy commented Jun 2, 2016

I’m not really the right person to judge the functional changes of this PR, but my one point of feedback is that your motivation doesn’t really outline why you want to be able to do this, which makes it harder to understand if this is the right solution. Your code example also doesn’t illustrate a real-world use-case.

}
if (!ancestor) {
return;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe combine these into a single if (view && ancestor) { … } ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can do that. I've just followed the style of the RCTMeasureLayout function.

Copy link
Contributor

Choose a reason for hiding this comment

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

That’s totally fair. I’m just providing some general code feedback, following existing styles is definitely a good choice 👍

@alloy
Copy link
Contributor

alloy commented Jun 2, 2016

While I left some general code feedback (just to be somewhat useful :)), I’ll stress again that this is just that, I’m not the one to decide if this is going to be accepted.

@alvaromb
Copy link
Contributor Author

alvaromb commented Jun 2, 2016

Sorry if the example isn't clear. Will try to explain why I need this.

Lets say we have a bunch of screens with TextInputs (something like a signup) that are contained by ScrollViews. In order to perform an automatic scroll to the focused TextInput, those ScrollViews can listen to the keyboard events. Once the keyboardWillShow event has been triggered, I can change the scroll contentInset and I can query which TextInput has the focus with the following function:

TextInput.State.currentlyFocusedField()

This will return a tag number which represents the node of the input focused. With ScrollView's scrollResponderScrollNativeHandleToKeyboard, I can use that tag to position the scroll view in order to display the focused input if it's hidden behind the keyboard.

However, the problem arises when you have more than one ScrollView listening to the keyboards at the same time. It might seem unusual, but it's actually quite easy to be in that case. We currently have this combination of scroll views and inputs into the navigation of all of our apps. First screen user inserts some data, then taps a button and navigates to another screen which has another scroll view and input. It's inside the Navigator stack, so both ScrollViews exist and both will receive the keyboard events. In this case, the ScrollView that do not contain the focused input as a descendant will try to scroll to it and crash (see https://github.com/APSL/react-native/blob/master/React/Modules/RCTUIManager.m#L1237).

The solution I came for this specific case was to export a functionality that, in the end, is already present in the measureLayoutRelativeToAncestor function. With this ancestor check I can query if the TextInput node is descendant of the ScrollView and then decide if I can scroll to that input or not.

I hope to have shed some light into the motivations of the PR, and thanks @alloy for your suggestions.

@wootwoot1234
Copy link

Any updates on this?

@alvaromb
Copy link
Contributor Author

I'll find some time today to perform the pending changes.

@ghost
Copy link

ghost commented Jun 20, 2016

Wow, just came to that issue, and the solution is already on the way! 👍

@alvaromb
Copy link
Contributor Author

I've added the detailed suggestions and rebased against master.

@grabcode
Copy link
Contributor

Thanks @alvaromb for supporting your great scrollview extension. Could we have some heads up from any guys at FB? @alloy maybe?

JosephDev pushed a commit to JosephDev/react-native-keyboard-aware-scroll-view that referenced this pull request Jun 28, 2016
- Change method name "viewIsAncestorOf" as "viewIsDescendantOf" according to PR facebook/react-native#7876
@wootwoot1234
Copy link

Any update on this?

@ghost ghost added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Jul 12, 2016
@JosephkimOS
Copy link

@alvarom any update on this PR?

@ghost ghost added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Jul 19, 2016
@alvaromb
Copy link
Contributor Author

I can update the PR @JosephkimOS, but I don't have any feedback from the Facebook team yet. Let's see if @mkonicek or @vjeux can help us here 😃

@ghost ghost added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Jul 20, 2016
@ghost ghost added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Aug 1, 2016
@irisSchaffer
Copy link

Any updates on this?

@javache
Copy link
Member

javache commented Aug 3, 2016

@facebook-github-bot shipit

@ghost ghost added CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. GH Review: accepted Import Started This pull request has been imported. This does not imply the PR has been approved. and removed GH Review: review-needed labels Aug 3, 2016
@ghost
Copy link

ghost commented Aug 3, 2016

Thanks for importing.

@ghost ghost added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Aug 3, 2016
@ghost ghost closed this in e52cab5 Aug 3, 2016
bartolkaruza pushed a commit to immidi/react-native that referenced this pull request Aug 3, 2016
Summary:
Sometimes is handy to check if a React node is a descendant of another node or not. For instance, I want to check if the focused `TextInput` is descendant of an specific `ScrollView`:

```js
const currentlyFocusedField = TextInput.State.currentlyFocusedField()
UIManager.viewIsAncestorOf(
  currentlyFocusedField,
  this.getInnerViewNode(),
  (isAncestor) => {
    if (isAncestor) {
      console.log('The focused field is a descendant of this ScrollView!')
    }
  }
)
```

This function uses the same strategy as the `measureLayout` method to check if one node is an ancestor of other node. As the `measureLayout` method, this is performed outside the main thread.

By now I've only implemented the iOS version and its tests, but if this function is going to be merged I'll implement the Android version too. I have objc experience but no Java or Android, so I prefer to validate this functionality before jumping into developing the Android part.
Closes facebook#7876

Differential Revision: D3662045

Pulled By: javache

fbshipit-source-id: b9668e8ea94fd01db76651f16243926cf9c2566f
@wootwoot1234
Copy link

Yeah! Shipit! :)

Thanks for doing this guys. What version or RN will we see this code in?

@javache
Copy link
Member

javache commented Aug 3, 2016

This should be in react-native 0.32

@JosephDev
Copy link

finally!

@alvaromb
Copy link
Contributor Author

alvaromb commented Aug 4, 2016

Thanks @javache!

I'm going to dig into Android code to send a PR with the same functionality.

rozele pushed a commit to microsoft/react-native-windows that referenced this pull request Aug 11, 2016
Summary:
Sometimes is handy to check if a React node is a descendant of another node or not. For instance, I want to check if the focused `TextInput` is descendant of an specific `ScrollView`:

```js
const currentlyFocusedField = TextInput.State.currentlyFocusedField()
UIManager.viewIsAncestorOf(
  currentlyFocusedField,
  this.getInnerViewNode(),
  (isAncestor) => {
    if (isAncestor) {
      console.log('The focused field is a descendant of this ScrollView!')
    }
  }
)
```

This function uses the same strategy as the `measureLayout` method to check if one node is an ancestor of other node. As the `measureLayout` method, this is performed outside the main thread.

By now I've only implemented the iOS version and its tests, but if this function is going to be merged I'll implement the Android version too. I have objc experience but no Java or Android, so I prefer to validate this functionality before jumping into developing the Android part.
Closes facebook/react-native#7876

Differential Revision: D3662045

Pulled By: javache

fbshipit-source-id: b9668e8ea94fd01db76651f16243926cf9c2566f
@haziqhafizuddin
Copy link

TextInput keep crush when goes to next page. i really need this issue to be fix. when is 0.32 roll out!?

@ghost
Copy link

ghost commented Aug 16, 2016

32-rc is out..

@cbcye
Copy link

cbcye commented Aug 18, 2016

Any updates on this?
tiy5ndw6t 27s krs8q 3 0

@alvaromb
Copy link
Contributor Author

@cbcye that screenshot does not belong to this issue. This PR was accepted and should land into RN 0.32 or 0.33.

mpretty-cyro pushed a commit to HomePass/react-native that referenced this pull request Aug 25, 2016
Summary:
Sometimes is handy to check if a React node is a descendant of another node or not. For instance, I want to check if the focused `TextInput` is descendant of an specific `ScrollView`:

```js
const currentlyFocusedField = TextInput.State.currentlyFocusedField()
UIManager.viewIsAncestorOf(
  currentlyFocusedField,
  this.getInnerViewNode(),
  (isAncestor) => {
    if (isAncestor) {
      console.log('The focused field is a descendant of this ScrollView!')
    }
  }
)
```

This function uses the same strategy as the `measureLayout` method to check if one node is an ancestor of other node. As the `measureLayout` method, this is performed outside the main thread.

By now I've only implemented the iOS version and its tests, but if this function is going to be merged I'll implement the Android version too. I have objc experience but no Java or Android, so I prefer to validate this functionality before jumping into developing the Android part.
Closes facebook#7876

Differential Revision: D3662045

Pulled By: javache

fbshipit-source-id: b9668e8ea94fd01db76651f16243926cf9c2566f
@cbcye
Copy link

cbcye commented Oct 2, 2016

@alvaromb i upgrade to RN 0.34 but still occur this problem.

@alvaromb
Copy link
Contributor Author

alvaromb commented Oct 4, 2016

@cbcye remove the node_modules/ folder and run npm i again. This could be your issue.

facebook-github-bot pushed a commit that referenced this pull request May 23, 2017
Summary:
Add the ability for UIManager to check if a node is an ancestor of anther one on Android like #7876 did on iOS
Closes #13129

Differential Revision: D4938319

Pulled By: hramos

fbshipit-source-id: abe20779be2142a1ea9ac46f52d8cd8609236419
@atlas1119
Copy link

i have react native .44 , but still occur this problem.
image

@alvaromb
Copy link
Contributor Author

alvaromb commented Jun 6, 2017

@atlas1119 I think that this hasn't landed in Android yet #13129

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. Import Started This pull request has been imported. This does not imply the PR has been approved.
Projects
None yet
Development

Successfully merging this pull request may close these issues.