react-native icon indicating copy to clipboard operation
react-native copied to clipboard

KeyboardAvoidingView has no effect on multiline TextInput

Open peacechen opened this issue 7 years ago • 113 comments

KeyboardAvoidingView only works with single-line TextInputs. When the multiline prop is set, KeyboardAvoidingView does not shift the TextInput at all.

Is this a bug report?

Yes

Have you read the Contributing Guidelines?

Yes

Environment

Environment: OS: macOS Sierra 10.12.6 Node: 7.0.0 npm: 3.10.8 Watchman: 4.7.0 Xcode: 9.1

Packages: (wanted => installed) react-native: 0.49.3 react: 16.0.0-beta.5

Target Platform: iOS (10.3)

Steps to Reproduce

  1. Use a <TextInput> component with multiline prop set.
  2. Wrap this in a ScrollView
  3. Wrap that in a KeyboardAvoidingView.

Expected Behavior

Multiline TextInput should scroll above the soft keyboard.

Actual Behavior

Soft keyboard covers multiline TextInput.

Reproducible Demo

import React, { Component } from 'react';
import { Text, TextInput, View, ScrollView, KeyboardAvoidingView, Keyboard} from 'react-native';

...

	render() {
		return (
			<KeyboardAvoidingView style={{flex:1}} behavior="padding" keyboardVerticalOffset={64}>
				<ScrollView keyboardShouldPersistTaps={'handled'}>
					<View style={{padding: 12}}>
						// various content to fill the page
						<Text style={{fontSize: 20, padding: 40}}>MESSAGE 1</Text>
						<Text style={{fontSize: 20, padding: 40}}>MESSAGE 2</Text>
						<Text style={{fontSize: 20, padding: 40}}>MESSAGE 3</Text>
						<Text style={{fontSize: 20, padding: 40}}>MESSAGE 4</Text>
						<Text style={{fontSize: 20, padding: 40}}>MESSAGE 5</Text>
						<Text style={{fontSize: 20, padding: 40}}>MESSAGE 6</Text>
						<Text style={{fontSize: 20, padding: 40}}>MESSAGE 7</Text>
						<Text style={{fontSize: 20, padding: 40}}>MESSAGE 8</Text>
						<Text style={{fontSize: 20, padding: 40}}>MESSAGE 9</Text>
						<Text style={{fontSize: 20, padding: 40}}>MESSAGE 10</Text>
					</View>
					<TextInput
						style={{padding: 4}}
						multiline={true}
						placeholder={'Type something here...'}
						onChangeText={this.updateMessage}
						value={this.state.message}
					/>
				</ScrollView>
			</KeyboardAvoidingView>
		);
	}

peacechen avatar Nov 14 '17 23:11 peacechen

I have a similar issue

Environment

node: 8.9.1 react: 16.0.0 react-native: 0.50.3 yarn: 1.3.2 watchman: 4.9.0 xcode: 9.1

Steps to Reproduce

  1. Use a <TextInput> component with autoCorrect="false" prop.
  2. Wrap that in a KeyboardAvoidingView with behavior="position" prop.
  3. Change keyboard type to Emoji keyboard

Expected Behavior

Multiline TextInput should be above the soft keyboard.

Actual Behavior

Soft keyboard covers TextInput.

Reproducible Demo

https://github.com/vivalaakam/react-native-issue

vivalaakam avatar Nov 15 '17 12:11 vivalaakam

Keyboard.addListener('keyboardWillChangeFrame', this.onKeyboardChange) doesn't`t fire when I change keyboard to emoji and fires when I change from emoji to other

vivalaakam avatar Nov 15 '17 12:11 vivalaakam

KeyboardAvoidingView works fine with multiline TextInput because i am using them myself. Initially they would not work for me. To solve my problem i removed the height on the TextInput and set the behavior to "padding". The "flex: 1" you have on the KeyboardAvoidingView might be the problem i think or its the scrollview. But KeyboardAvoidingView definitely works fine with multiline.

jibberilins avatar Nov 27 '17 18:11 jibberilins

Referring to my snippet posted above, there's no height on the TextInput, and KeyboardAvoidingView's behavior is set to padding.

Its style needs flex:1 to allow the ScrollView to take up the entire height.

Try the code with and without multiline set. It fails with multiline set, but the same code works for single line TextInputs.

peacechen avatar Nov 27 '17 19:11 peacechen

Same problem here!

hoscarcito avatar Jan 19 '18 07:01 hoscarcito

@peacechen I have exactly the same problem like you. Need to add flex: 1 for the ScrollView as the wrapper. And it works if I remove the prop multiline={true}. Any solution for this?

fadlykayo avatar Mar 21 '18 11:03 fadlykayo

The same issue。 my code is same as the author. there is a multiline TextInput in ScrollView. outsider with a KeyboardAvoidingView wrapper.

sherxia92 avatar May 10 '18 04:05 sherxia92

If anyone still is looking for a fix, you could try

<View style={{position:relative}}>
    <TextInput ref='multilineText' value={this.state.textValue} 
        onChangeText={(textValue) => this.setState({textValue})}/>
    <TextInput style={{ color:'transparent', position: 'absolute', width: '100%', height: '100%' }}
        placeholderTextColor='transparent'
        onFocus={() => setTimeout(() => this.refs.multilineText.focus(), 1000) } 
        value={this.state.textValue}
        onChangeText={(textValue) => this.setState({textValue})}
    />
</View>

Its a dirty hack but it does the job, what it does it when user clicks on the input it would be clicking on the single line and the keyboard will scroll to that line then after 1 seconds (you can adjust this, i just found 1 seconds to be good with our app) it would focus on the multiline. The value and onChangeText makes sure that when the user star typing they would have the same value except the single line has transparent text.

The downside is when a user clicked the multiple line, the cursor wont go to the location they clicked but it would go to the end.

monmonja avatar May 18 '18 06:05 monmonja

@monmonja That's a creative work-around. I wonder if it could also be done by setting the multiline prop to a state variable that is changed during onFocus. That would eliminate the second TextInput.

I don't see the multiline prop in the first TextInput, but I assume it's supposed to be in there.

peacechen avatar May 18 '18 13:05 peacechen

Has anyone found a good solution for this?

kfroemming-cb avatar Jun 29 '18 15:06 kfroemming-cb

@peacechen I tried to implement your suggestion but it has a strange effect and doesn't work. Something's flickering and the keyboard eventually disappears. I am also looking for a solution to this. Cannot apply @monmonja 's workaround because I'm using redux-form. This makes it much more complicated for this workaround. I can confirm that all is working fine when I remove the multiline prop. I wrapped the whole application with KeyboardAvoidingView and my multiline TextInput is at the end of the form like in the author's example. I have no height applied to the TextInput which in a few cases can cause issues. I am using react-native: 0.53.0

chmielot avatar Jul 02 '18 21:07 chmielot

same problem here and still have no solution

Hsuer avatar Jul 09 '18 03:07 Hsuer

I too facing the same issue. It works fine if multiline is set to false and not if set to true. My TextInput does not have any height. Any solutions??

sndkd avatar Aug 01 '18 11:08 sndkd

A workaround for this is to make a reference to the parent scrollview and call its scrollTo method to the multilined TextInput coordinates whenever onFocus is called.

<KeyboardAvoidingView
   style={{ flex: 1 }}
   behavior="padding"
>
  <ScrollView ref={component => { this.myScrollView = component; }}>
    <TextInput 
       multiline
       onFocus={() => this.myScrollView.scrollTo({ x: 0, y: 750, animated: true })} // <- your coordinates here
    />
  </ScrollView>
</KeyboardAvoidingView>

jasonchoibiz avatar Aug 17 '18 02:08 jasonchoibiz

same problem here only on IOS textinput multiline has no effect on keyboardavoidingview

it is working fine on android

lucasboleli avatar Aug 17 '18 17:08 lucasboleli

This has been quite frustrating for us as well.. Seems like the only consistent way to do this is by scrolling manually as @jasonchoibiz suggested.

It's an ugly workaround though! ☹️

amsul avatar Aug 24 '18 16:08 amsul

there is news about this problem?

robertobrogi avatar Sep 12 '18 15:09 robertobrogi

Still having this. Tried the suggested solutions.

luco avatar Sep 27 '18 15:09 luco

same problem here

mitevdev avatar Oct 01 '18 09:10 mitevdev

Same issue, here's a simple snack for anyone to play with: https://snack.expo.io/r1qpj0k5Q

Jmedders avatar Oct 01 '18 17:10 Jmedders

Same issue, here's a simple snack for anyone to play with: https://snack.expo.io/r1qpj0k5Q

I've tried this and it works:

https://github.com/baijunjie/react-native-input-scroll-view

mitevdev avatar Oct 02 '18 14:10 mitevdev

react-native version 0.56.1 same problem....

linoleum00 avatar Oct 17 '18 16:10 linoleum00

it is working;

<KeyboardAvoidingView behavior="padding" style={Platform.OS !== 'android' && { flex: 1 }}> 
  <ScrollView>
      ... 
      <TextInput ... />
      ...
  </ScrollView>
</KeyboardAvoidingView>

recepkoseoglu avatar Nov 12 '18 16:11 recepkoseoglu

@recepkoseoglu It works on non-multiline Inputs. Try on multiline.

luco avatar Nov 13 '18 19:11 luco

It's working if we use <View> to wrap the content instead of <ScrollView>, not ideal if you have many TextInputs though.

<KeyboardAvoidingView
    behavior={Platform.OS === "ios" ? "padding" : null} 
    style={{ flex: 1 }}
>
    <View style={{ flex: 1, justifyContent: "flex-end" }}>
        ...
        <TextInput multiline />
        <View style={{ flex: 1 }} /> // Use this to take up bottom spacing
    </View>
</KeyboardAvoidingView>

mk-nickyang avatar Nov 14 '18 04:11 mk-nickyang

No fix yet?

luco avatar Jan 29 '19 01:01 luco

RN 0.57... confirm same issue.

ankhanguit avatar Jan 29 '19 10:01 ankhanguit

still same issue here. any solution?

boraerbasoglu avatar Feb 21 '19 10:02 boraerbasoglu

I switched to "React-Native Keyboard Manager" and it works. Just install and your issues are solved

matteocollina avatar Feb 28 '19 15:02 matteocollina

This is really causing a lot of problems. Any updates on this issue? I have tried using the libraries mentioned above but each of them come with sacrifices in user experience.

kfroemming-cb avatar Mar 07 '19 22:03 kfroemming-cb