Closed ide closed 9 years ago
I'm not sure I understand. You can do .blur() on Text ref right now. Do you want to do blur() on an arbitrary View?
Yeah, it blurs any descendant that has focus. The descendant could be a TextInput but could also be any other kind of input element that can become the first responder.
You can actually call blur() on a View today. See NativeMethodMixin::blur. Can you tell me if it's doing what you want?
ping @ide
Confirmed that this.refs.parentView.blur
does not blur its child views. Where this would be handy is in the navigator stack where a scene will lose focus without being unmounted, and you want to make sure to blur all of its text fields. So instead of
this.refs.textInput1.blur();
this.refs.textInput2.blur();
this.refs.textInput3.blur();
you want to write
this.refs.container.blur();
This does seem like it would be useful! Another issue came up (referenced above) where this would solve the problem. cc @ide @vjeux
@brentvatne I came up with a simple solution for this internally where I wrote a component that essentially just extends UIView
and blurs all of the subviews on touch. Here is the guts of it:
@implementation KBCloserView
- (void)didMoveToSuperview
{
self.userInteractionEnabled = TRUE;
[super didMoveToSuperview];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
for (UIView *subview in self.subviews) {
[subview endEditing:YES];
}
}
@end
So I just convert my container View
's to <KBCloserView>
components, and :boom: tap anywhere in the view to close the keyboard.
I share this because I think adding a closeKeyboardOnPress
type property to the RN View
component, which just does the above, would be simple and solve this problem entirely without having to go through the effort of changing how blur
works (I personally like that it only blurs the specific input).
Nice on @dhrrgn! Seems simple enough. Might be worth putting into a library on npm until a solution is integrated into core
@brentvatne I will do that tomorrow...right after I figure out how to create an Xcode project people can just add to their's (bit of an Xcode "noob") haha. (Side note: it would be awesome if their was a "Creating Distributable Native Components" section of the docs for this sort of thing).
@dhrrgn - I have something about that on my blog: Packaging a React Native component, I hesitated to add it to the docs because it seemed like a temporary solution, but we haven't worked out a better one yet (aside from react-native new-library
from within a React Native project, in order to create a skeleton bridge module component - you could do this and just change it up accordingly rather than create a new project from scratch as I mention in my blog post)
@brentvatne Awesome, thanks.
Any updates on that? Calling blur
on a view should act like endEditing
as per @ide suggestion. If not, maybe worth adding another method.
My use case:
Using @brentvatne modal with click backdrop to dismiss
feature. When the keyboard is opened, I'd prefer closing the keyboard instead of dismissing the modal so user has the ability to continue editing. Not all keyboard types are provided done
button as of now (e.g. numpad
) so it gets tricky.
@grabbou - do you have time to make the changes that @ide mentioned above and submit a PR?
Yeah, can do. Just need to dig into the source code as I haven't contributed yet but would love to.
Another thing worth noticing is that the method signature is actually endEditing:force
instead of mentioned :animated
.
After doing a couple of more tests it looks like the this.refs.mainView.blur()
blurs all the child TextViews (including TextInputs that are inside another view).
Sample structure returned from render:
<View ref='modal'>
<View style={styles.container}>
<TextInput .... />
<TextInput .... />
</View>
</View>
and the invocation:
this.refs.modal.blur();
@ide - what do you think about @grabbou's observation above?
Not sure why that's happening. Maybe something changed. Feel free to close this if it just works now.
@ide - seems to be a false alarm, still not working for me with 0.5: https://rnplay.org/apps/SwEnTw - tried it against master as well, same thing: https://rnplay.org/apps/AxZnJw
@grabbou - can you reproduce that fix on rnplay.org?
Still an outstanding issue as far as I can tell
Not working for me either - an outstanding issue I'm afraid.
Anyone up for fixing this? Would be a great way to learn about some of the React Native internals
It is still outstanding, I made another rnplay: https://rnplay.org/apps/aAb8aA/ to showcase the problem with 0.6.0 and can reproduce with 0.8.0-rc, I'm going to give this a try with my limited Objective-C skills.
It looks like nobody on the team at Facebook has a need for this at the moment so I've tagged it as Community Responsibility :smile:
@brentvatne So i went off and tried to do it, and I have something working but wanted to show you first as this is my first time messing with the internals so want to see if I should change my approach.
In NativeMethodsMixin.js I added the following under blur():
endEditing: function() {
RCTUIManager.endEditing(findNodeHandle(this));
}
In RCTUIManager.m I did the following:
- (void)endEditingForShadowView:(NSNumber *)reactTag manager:(RCTUIManager *)uiManager viewRegistry:(RCTSparseArray *)viewRegistry
{
RCTShadowView *shadowView = uiManager.shadowViewRegistry[reactTag];
for(RCTShadowView *subview in [shadowView reactSubviews]) {
if([[subview reactSubviews] count] > 0) {
[uiManager endEditingForShadowView:subview.reactTag manager:uiManager viewRegistry:viewRegistry];
} else {
UIView *view = viewRegistry[subview.reactTag];
[view resignFirstResponder];
}
}
}
RCT_EXPORT_METHOD(endEditing:(NSNumber *)reactTag)
{
if (!reactTag) return;
[self addUIBlock:^(__unused RCTUIManager *uiManager, RCTSparseArray *viewRegistry){
[uiManager endEditingForShadowView:reactTag manager:uiManager viewRegistry:viewRegistry];
}];
}
My test case:
blurFields() {
this.refs.xview.endEditing();
}
<View style={{flex: 1}} ref="xview">
<ScrollView ref="scrollView">
<View testProp={true}>
<TextInput ref="field1" style={{backgroundColor: 'red', width: 100, height: 20}} />
<TextInput ref="field2" style={{backgroundColor: 'blue', width: 100, height: 20, marginTop: 20}} />
<View>
<TextInput ref="field3" style={{backgroundColor: 'green', width: 100, height: 20, marginTop: 20}} />
</View>
<TouchableHighlight onPress={() => this.blurFields()}>
<Text>Blur fields</Text>
</TouchableHighlight>
</View>
</ScrollView>
</View>
Everything seems to work okay and the functionality works as expected. What do you think? I'll submit a proper PR if you think it's good.
@josebalius - this looks very reasonable to me, @tadeuzagallo what do you think?
One comment about the API: it would be nice if this was just a modification of blur
so that blur
would affect all children as well.
@brentvatne roger on the API, i thought about the same thing shouldn't be a problem. If @tadeuzagallo is fine with the code i'll submit the PR with an API like this.refs.parentView.blur(true)
true
for deep search, if not true
then it will act the same as it does now which is tries to blur the active text field.
Actually maybe we don't need the extra param at all, if it's on a text field that you are calling it on the loop should have to search once so I think that works as well.....we can just replace the blur functionality altogether.
@josebalius - yeah I agree, if it's just a TextField then we don't have to be concerned about traversing any children
This can be closed, no? https://github.com/facebook/react-native/blob/master/Libraries/Utilities/dismissKeyboard.js
var dismissKeyboard = require('dismissKeyboard')
...
onClose: function() {
dismissKeyboard();
}
@wluxion Looks interesting, how do you require the dismissKeyboard Utility in a project? I didn't see Utilities or that particular one in the docs. Will it work on iOS and Android?
We are exposing TextInputState in #3308 which will allow you to do this too. I'm not sure it's worth exposing this one line function as it will increase API surface area, if you believe it's important then feel free to chime in on that PR! Thanks @wluxion for the heads-up.
@brentvatne Looks great, I look forward to it.
@brentvatne Any update on this? I am upgrading a couple of projects to the latest RN and running into blur issues not hiding the keyboard, do we have docs on the proper way to do it?
@josebalius - hmmm I'm not sure about this, could you put together a small example and create a new issue?
If you have two text inputs in a container view, calling
container.blur()
could make both of the text inputs try to resign their first responder status. In UIKit this is built-in as-[UIView endEditing:animated]
. This way you can just blur the root view if you want the keyboard to go away.