Closed yelled3 closed 8 years ago
@yelled3 I managed to get the input focus scroll. Let me know if I can help you with something :relaxed:
@alvaromb it would be great if you can share an example in https://rnplay.org/ or a gist. cheers :-)
@yelled3 I'll try to put an example this afternoon :)
@yelled3 I am also building a similar messenger like UI. I am able to get scrollResponderScrollNativeHandleToKeyboard
to scroll to input box, but by using ScrollView
my TextInput
goes below viewport when keyboard is not shown (I am using a ListView
to render messages). How are you sticking the TextInput to device screen bottom?
The code from here- http://stackoverflow.com/a/32593814 works for me for reacting to keyboard show.
My Layout looks like-
<ScrollView>
<ListView/>
</TextInput>
</ScrollView>
@aakashbapna
How are you sticking the TextInput to device screen bottom?
I wasn't able to make it work. I used the same layout as you did.
I really don't like the fact that you must place the TextInput
inside the ScrollView
- seems very limiting.
either the text input will not be position correctly or that the screen will not scroll to the input correctly. not sure what I'm doing wrong.
apparently @alvaromb has a working example :-)
My solution is a bit hacky. I have a custom scroll component:
import React, { ScrollView, PropTypes, DeviceEventEmitter } from 'react-native'
import StyleSheetPropType from 'react-native/Libraries/StyleSheet/StyleSheetPropType'
import ViewStylePropTypes from 'react-native/Libraries/Components/View/ViewStylePropTypes'
class KeyboardAwareScrollView extends React.Component {
constructor (props) {
super(props)
this.state = {
keyboardSpace: 0,
}
this.updateKeyboardSpace = this.updateKeyboardSpace.bind(this)
this.resetKeyboardSpace = this.resetKeyboardSpace.bind(this)
}
// Keyboard actions
// TODO: automatically handle TabBar height instead of using props
updateKeyboardSpace (frames) {
const keyboardSpace = (this.props.viewIsInsideTabBar) ? frames.endCoordinates.height - 49 : frames.endCoordinates.height
this.setState({
keyboardSpace: keyboardSpace,
})
}
resetKeyboardSpace () {
this.setState({
keyboardSpace: 0,
})
}
componentDidMount () {
// Keyboard events
DeviceEventEmitter.addListener('keyboardWillShow', this.updateKeyboardSpace)
DeviceEventEmitter.addListener('keyboardWillHide', this.resetKeyboardSpace)
}
componentWillUnmount () {
// TODO: figure out if removeAllListeners is the right thing to do
DeviceEventEmitter.removeAllListeners('keyboardWillShow')
DeviceEventEmitter.removeAllListeners('keyboardWillHide')
}
/**
* @param extraHeight: takes an extra height in consideration.
*/
scrollToFocusedInput (event, reactNode, extraHeight = 49) {
const scrollView = this.refs.keyboardScrollView.getScrollResponder()
scrollView.scrollResponderScrollNativeHandleToKeyboard(
reactNode, extraHeight, true
)
}
render () {
return (
<ScrollView
ref='keyboardScrollView'
keyboardDismissMode='interactive'
contentInset={{bottom: this.state.keyboardSpace}}
showsVerticalScrollIndicator={true}
style={this.props.style}>
{this.props.children}
</ScrollView>
)
}
}
KeyboardAwareScrollView.propTypes = {
style: StyleSheetPropType(ViewStylePropTypes),
children: PropTypes.node,
viewIsInsideTabBar: PropTypes.bool,
}
export default KeyboardAwareScrollView
Then I put the TextInput
components inside this scroll. All of the inputs implement the onFocus
method, and it exposes it's node handle. I'm using a library called tcomb to generate the Form
component, so this is why you see the this.refs.form.refs.input.refs
line below:
// Inside TextInput
onFocus: this._scrollToInput.bind(this, 'input_name'),
// 'private' method
_scrollToInput (inputName, event) {
if (this.props.onFocus) {
this.props.onFocus(
event,
React.findNodeHandle(this.refs.form.refs.input.refs[inputName])
)
}
}
Then, in the component that renders both the form and the custom list view I can call the scrollToFocusedInput
method of the KeyboardAwareScrollView
component with the node handle of the input:
<KeyboardAwareScrollView
ref='scroll'
style={styles.container}
viewIsInsideTabBar={true}>
<CustomForm ref='form'
onFocus={(event, reactNode) => {
this.refs.scroll.scrollToFocusedInput(event, reactNode)
}}
/>
</KeyboardAwareScrollView>
This is a very hacky and dirty solution, but it's working so far at this moment. We're thinking about a better integration of this scroll component with the https://github.com/gcanti/tcomb-form-native library, which is quite awesome.
In the end, the key is to send the React node handle of the input to the scrollToFocusedInput
of the custom scroll view. Then I have to admit that some times the input gets hidden behind the keyboard, this is why I have an extra parameter to add some height to the calculation.
I'm not very proud of this code at all, but if this can help somebody to achieve a better solution, I'll be more than happy.
Let me know if you need something else :+1:
@alvaromb thank you for the thorough answer!
Then I have to admit that some times the input gets hidden behind the keyboard
I still need to try this out - maybe I can solve this. @ide any idea why this happens...
@yelled3 if I put a timeout when calling scrollResponderScrollNativeHandleToKeyboard
, the input doesn't get hidden when the keyboard appears.
This is now my new scroll function:
scrollToFocusedInput: function (event, reactNode, extraHeight = 49) {
const scrollView = this.refs.keyboardScrollView.getScrollResponder()
this.setTimeout(() => {
scrollView.scrollResponderScrollNativeHandleToKeyboard(
reactNode, extraHeight, true
)
}, 220)
},
I know it's a hack but... ¯(ツ)/¯
It does make sense because the scroll responder is acting when the scroll view contentInset
is being changed, so the handle needs to wait and act when the scroll view has the new inset set.
@alvaromb perhaps using runAfterInteractions
will solve this (or maybe requestAnimationFrame
scrollToFocusedInput: function (event, reactNode, extraHeight = 49) {
const scrollView = this.refs.keyboardScrollView.getScrollResponder()
InteractionManager.runAfterInteractions(() => {
scrollView.scrollResponderScrollNativeHandleToKeyboard(
reactNode, extraHeight, true
)
})
},
see: http://facebook.github.io/react-native/docs/timers.html#interactionmanager
Thanks @yelled3! but unfortunately only setTimeout
is working.
@alvaromb sorry for the delay, I finally got to thoroughly check your solution;
as far as I can tell, your solution doesn't handle keyboardDismissMode='interactive'
correctly.
when opening the keyboard, the TextInput
jumps from original position to keyboard opened position.
and when I scroll down on the ScrollView
- you can see the keyboard is being slowing lowered until it reaches the bottom and only then the TextInput
jumps to the bottom.
For this to work correctly, the TextInput
should always be attached to the top of the keyboard.
from: https://github.com/datwelk/RDRStickyKeyboardView
perhaps, adding a RN wrapper for RDRStickyKeyboardView
(or whatever works best) is the way to go?
WDYT?
@alvaromb I'm interested in implementing a similar solution to what you've already got. I'm also using tcomb for form building and think something similar to your implementation could be a nice feature toggle. Would you mind sharing what you've got so far in a gist?
Any better solution for this issue?? Or maybe a completely custom keyboard written in JS? lol
@yelled3 _scrollToInput { var scrollView = this.refs.myScrollView.getScrollResponder(); var scrollResponder = scrollView.getScrollRef();
scrollResponder.scrollResponderScrollNativeHandleToKeyboard( React.findNodeHandle(this.refs.myInput), 0, // adjust depending on your contentInset /* preventNegativeScrollOffset */ true );
After you move the screen up how can you move it down after keyboard is hidden?
@georgi-kovachev not sure I understand...
@jrans although, https://github.com/jrans/react-native-smart-scroll-view/ seems like a very elegant solution - from what I can tell, it doesn't solve what we're talking about:
I'm trying to implement a classic messenger UI
see the gif in: https://github.com/facebook/react-native/issues/3195#issuecomment-147427391
@yelled3 my bad! Misread things! Yes I had exactly the same problem with interactive mode! So disabled it! Only thing keyboardWillChangeFrame does is time how long they take to scroll..
+1 any solutions?
This https://github.com/facebook/react-native/issues/3195#issuecomment-146518331 works for me @imton, but it's not the most elegant solution ever.
@alvaromb for interactive drag?
I tried your code but don't know how to make it work actually. I want a sticky field to the keyboard like shown in above.
Would you mind showing me how to archive that? Really appreciate it.
Best, Gaston
Sent from my iPhone
On Jan 14, 2016, at 12:56 PM, Álvaro Medina Ballester notifications@github.com wrote:
This #3195 (comment) works for me @imton, but it's not the most elegant solution ever.
— Reply to this email directly or view it on GitHub.
It worked for me. Thanks.
Implementing this worked for me in react-native 0.18.1
Looks like there's a real need for this.
Ideal solution IMO would be to add {position: fixed, bottom: 0}
to an element.
@pjcabrera the example works great on Simulator but unfortunately not in my actual 4S device - it actually hides the View
. Any suggestions?
Just a quick update, I've added TextInput
auto scroll feature into my react-native-keyboard-aware-scroll-view
component: https://github.com/APSL/react-native-keyboard-aware-scroll-view/releases/tag/v0.1.0
react-native-keyboard-aware-scroll-view looks great!
@facebook-github-bot answered
@facebook-github-bot answered
Closing this issue as @mkonicek says the question asked has been answered. Please help us by asking questions on StackOverflow. StackOverflow is amazing for Q&A: it has a reputation system, voting, the ability to mark a question as answered. Because of the reputation system it is likely the community will see and answer your question there. This also helps us use the GitHub bug tracker for bugs only.
I'm trying to implement a classic messenger UI; I want the scroll view to respond to the keyboard opening.
I tried a few solutions:
Keyboard Events
The first was using
keyboardWillShow
&keyboardWillHide
event andAnimated.timing
to toggle the scrollview bottom padding. fairly simple.I also tried using
keyboardWillChangeFrame
to handleScrollView''s
keyboardDismissMode="interactive"` - but it will not be fire at all. after a short research it seems like it's an open issue since iOS 8. see: http://stackoverflow.com/questions/19118921/moving-a-bar-with-uiscrollviewkeyboarddismissmodeinteractive can someone confirm this?Scroll Responder Hooks
Although, completely undocumented I was able to find
scrollResponderScrollNativeHandleToKeyboard
source: http://stackoverflow.com/a/30609066/2857906
I'm either not using this correctly, or this still has some issues (see: https://github.com/facebook/react-native/issues/355) but this seems to not be working consistently... also notice that in this approach, the
TextInput
must be embedded inside theScrollView
.It would be great to have a working example of this. maybe add it to
UIExplorer
...@ide @brentvatne /cc