Home > Software design >  How to use Scrollview with KeyboardAvoidingView
How to use Scrollview with KeyboardAvoidingView

Time:03-23

I am a new to react native and i wonder how to use scrollView with keyboardAvoid in the following scene.I have searched for some relevant information, but still have no clue.

Following picture may be more intuitive then explain.

enter image description here

import  React,{useRef,useEffect,useState} from 'react';
import { Text, View, StyleSheet,TextInput,ScrollView,KeyboardAvoidingView,TouchableOpacity } from 'react-native';

export default function App() {
  const [selectedItem,setSeLectedItem] = useState(null)
  const [userTyping,setUserTyping] = useState(false);

    const selected = (index) => {
    setUserTyping(true)
      setSeLectedItem(index)
    }
  const onBlur=()=>{
    setUserTyping(false)
  }

  return (
    <View style={styles.container}>
            <KeyboardAvoidingView style={{flex:1}}>
            <ScrollView style={styles.scroll} >
                    {
                        ['1', '2', '3', '4','5','6','7'].map((item,index) => (
                            <TouchableOpacity onPress={()=>selected(index)} key={item}>
                            <View style={[styles.itemWrapper,selectedItem===index &&styles.selectedItem]}>
                                <Text style={styles.itemText}>TEST {item}</Text>
                                {
                                    (selectedItem===index)&&userTyping&&
                                    <InputFC 
                                        style={styles.itemInput} 
                                        placeholder='NO TEXT' 
                                        placeholderTextColor={'white'} 
                                        autoCapitalize={'none'}
                                        onBlur={onBlur}
                                    />
                                }                           
                            </View>
                        </TouchableOpacity>
                        ))
                    }
                </ScrollView>
            </KeyboardAvoidingView>
    </View>
  );
}

const InputFC = (props) => {
    const {style,placeholder,placeholderTextColor,autoCapitalize,onBlur} = props
    const inputRef = useRef(null);
    
    useEffect(()=>{
        if(inputRef.current) inputRef?.current?.focus()
    })
    
    return (
    <TextInput 
        style={style} 
        ref={inputRef}
        placeholder={placeholder}
        placeholderTextColor={placeholderTextColor} 
        autoCapitalize={autoCapitalize}
    onBlur={onBlur}
    />)
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#24292e',
    },
    scroll: {
        flex: 1,
        paddingHorizontal: 20,
    },

    itemWrapper:{
        width: '100%',
        paddingLeft:20,
        paddingVertical:20,
        marginBottom: 20,
        backgroundColor: '#6b6965',
        borderRadius:20,
    },
    itemText:{
        fontSize:20,
        fontWeight:'bold',
        color:'white',
        alignItems:'center',
        justifyContent:'center',
        marginBottom:5,
    }
    ,
    itemInput:{
        fontSize:20,
        color:'white',
    },
    selectedItem:{
        borderWidth:3,
        borderColor:'#2188ff'
    }
});

Simplified Demo online:

https://snack.expo.dev/@bravo20203/demo-about-scrollview

Thanks.

CodePudding user response:

You can make this work by changing the flex: 1 to different components and by adding

behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
style={{flex: 1}}

to the KeyboardAvoidingView. I have also wrapped your content into a SafeAreaView so it does not go into the header on iOS.

Since you are dynamically expanding the TextInput on press, which changes its height, I have added a keyboardVerticalOffset to the KeyboardAvoidingView and made the overflow visible.

The final code is as follows.

import React, { useEffect, createRef, useState, useRef } from 'react';
import { useHeaderHeight } from "@react-navigation/elements";
import {
  Text,
  View,
  KeyboardAvoidingView,
  ScrollView,
  TextInput,
  Platform,
  TouchableOpacity,
  StyleSheet,
  SafeAreaView
} from 'react-native';

export default function App() {
  const [selectedItem,setSeLectedItem] = useState(null)
  const [userTyping,setUserTyping] = useState(false);

    const selected = (index) => {
    setUserTyping(true)
      setSeLectedItem(index)
    }
  const onBlur=()=>{
    setUserTyping(false)
  }

  return (
    <SafeAreaView style={styles.container}>
            <KeyboardAvoidingView
          behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
          style={Platform.OS === 'ios' && {flex: 1}}
          keyboardVerticalOffset={30}
      >
            <ScrollView style={styles.scroll}>
                    {
                        ['1', '2', '3', '4','5','6','7'].map((item,index) => (
                            <TouchableOpacity onPress={()=>selected(index)} key={item}>
                            <View style={[styles.itemWrapper,selectedItem===index &&styles.selectedItem]}>
                                <Text style={styles.itemText}>TEST {item}</Text>
                                {
                                    (selectedItem===index)&&userTyping&&
                                    <InputFC 
                                        style={styles.itemInput} 
                                        placeholder='NO TEXT' 
                                        placeholderTextColor={'white'} 
                                        autoCapitalize={'none'}
                    onBlur={onBlur}
                                    />
                                }                           
                            </View>
                        </TouchableOpacity>
                        ))
                    }
                </ScrollView>
            </KeyboardAvoidingView>
    </SafeAreaView>
  );
}

const InputFC = (props) => {
    const {style,placeholder,placeholderTextColor,autoCapitalize,onBlur} = props
    const inputRef = useRef(null);
    
    useEffect(()=>{
        if(inputRef.current) inputRef?.current?.focus()
    })
    
    return (
    <TextInput 
        style={style} 
        ref={inputRef}
        placeholder={placeholder}
        placeholderTextColor={placeholderTextColor} 
        autoCapitalize={autoCapitalize}
    onBlur={onBlur}
    />)
}

const styles = StyleSheet.create({
    container: {
        backgroundColor: '#24292e',
    flex: 1
    },
    scroll: {
        paddingHorizontal: 20,
    overflow: "visible",
    },

    itemWrapper:{
        width: '100%',
        paddingLeft:20,
        paddingVertical:20,
        marginBottom: 20,
        backgroundColor: '#6b6965',
        borderRadius:20,
    },
    itemText:{
        fontSize:20,
        fontWeight:'bold',
        color:'white',
        alignItems:'center',
        justifyContent:'center',
        marginBottom:5,
    }
    ,
    itemInput:{
        fontSize:20,
        color:'white',
    },
    selectedItem:{
        borderWidth:3,
        borderColor:'#2188ff',
    }
});

I have updated your snack here. Notice that I have tested this on iOS only.

If the keyboard is opened on select, the selected Input is now fully visible.

  • Related