I'am working on an App for some algorithms. Something like "Question" if yes, then x and if no then y. Some I created a Component, for a single algorithm step.
Some of the answers are not only yes or no, so i added a optional text input to my component. If as possible answer in the algorithm "TextInput" there should be a TextInput Element and a Button with ok. After clicking Ok the TextInput should become a fixed Text. But after every keystroke the keyboard closes.
I found out, that this beahvior starts, after adding value and onTextChanged to the TextInput. But in other projects i got this exactly the same way working. Why? Can anyone help?
Here is my code for the component:
import { AutoSizeText, ResizeTextMode } from 'react-native-auto-size-text';
import { Dimensions, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native';
import { useState } from 'react';
export default function SingleAlgorithmStep(props) {
const step = props.step; //Inhalt des akutell auszuführenden Schritts
const stepsDone = props.stepsDone; //Array mit bereits erledigten Schritten
const clickedButtons = props.clickedButtons; //Array mit den bereits ausgewählten Buttons
const currentAlgorithmJson = props.algorithmJson; //Aktuellen Algorithmus von den Props auslesen
const [textInputValue, changeTextInput] = useState('');
let buttons = []; //Array, was die Texte und die Anzahl der Buttons für diesen Step beinhaltet
var buttonWidth = (Dimensions.get('window').width - 20); //Breite eines Buttons entspricht der Bildschirmbreite abzüglich Rand
if (Object.keys(step["Action"]).length > 1) {
buttonWidth = (buttonWidth - (Object.keys(step["Action"]).length - 1) * 10) / Object.keys(step["Action"]).length;
} //Falls mehrere Buttons vorhanden sind, soll zwischen den Buttons etwas Platz sein und trotzdem sollen alle gleich groß sein
for (const buttonText in step["Action"]) {
const id = step["Question"] " : " buttonText; //Einmalige ID erzeugen
buttons = buttons.concat(
<TouchableOpacity key={id} style={[styles.button, { width: buttonWidth, backgroundColor: clickedButtons.includes(id) ? "limegreen" : "dodgerblue" }]} onPress={() => {
if (clickedButtons.filter(oldId => oldId.includes(step["Question"])).length > 0) {
//Falls auf einen bereits erledigten Schritt zurückgegangen wird...
props.actualizeButtons(clickedButtons.splice(0, stepsDone.indexOf(step)).concat(id)); //Gewählte Buttons werden bis zum Index des Schrittes beibehalten und der neue Button wird ergänzt
props.actualizeSteps(stepsDone.splice(0, stepsDone.indexOf(step) 1).concat(currentAlgorithmJson[step["Action"][buttonText]])); //Schritte werden bis zum Index des aktuellen Steps beibehalten und der nächste Schritt ergänzt
}
else {
props.actualizeButtons(clickedButtons.concat(id)); //ID zum Array hinzufüge, um angeklickte Buttons zu markieren
props.actualizeSteps(stepsDone.concat(currentAlgorithmJson[step["Action"][buttonText]])); //Nächsten Schritt einfügen
}
}}>
<AutoSizeText style={[styles.buttonText, { width: buttonWidth }]} fontSize={18} minFontSize={18} numberOfLines={3} mode={ResizeTextMode.min_font_size}>{buttonText === "TextInput" ? "Ok" : buttonText}</AutoSizeText>
</TouchableOpacity>
);
} //Jeden Button aus dem JSON als Element zur Liste hinzufügen, um so dynamisch die Anzahl der Button und den Button Text zu regulieren
return (
<View style={{ marginBottom: 15 }}>
<AutoSizeText style={styles.Question} fontSize={24} minFontSize={21} numberOfLines={5} mode={ResizeTextMode.min_font_size}>{step["Question"]}</AutoSizeText>
{Object.keys(step["Action"]).includes("TextInput") ? !clickedButtons.includes(step["Question"] " : " "TextInput") ? <TextInput key={Math.random()} style={styles.input} value={textInputValue} onChangeText={(textInputValue) => changeTextInput(textInputValue)} placeholder={step["Question"]}></TextInput> : <Text>{textInputValue}</Text> : null}
<View style={{ flex: 1, flexDirection: 'row', justifyContent: 'space-between' }}>
{buttons}
</View>
</View>
)
}
const styles = StyleSheet.create({
Question: {
width: Dimensions.get('window').width - 20,
minHeight: 40,
borderColor: 'black',
borderWidth: 2,
textAlign: 'center',
},
input: {
borderWidth: 1,
borderColor: 'black',
width: '100%',
fontSize: 18,
padding: 5,
marginTop: 5,
},
button: {
marginTop: 10,
minHeight: 30,
justifyContent: 'space-around'
},
buttonText: {
textAlign: 'center',
color: 'white',
minHeight: 30,
textAlignVertical: 'center'
}
});
CodePudding user response:
This is the default behavior when TextInput is a child component to scrollable components, ScrollView
, FlatList
OR SectionList
.
Make always keyboard persist tap as below:
<FlatList
keyboardShouldPersistTaps="always"
//...otherProps
/>
Then remove the key
prop which is set to Math.random()
. The random number value is dynamic for each rerender and doesn't provide any performance benefit.
<TextInput
//key={Math.random()} - Key should not be random number
style={styles.input}
value={textInputValue}
onChangeText={(textInputValue) => changeTextInput(textInputValue)}
placeholder={step["Question"]}
/>;
Here working snack - https://snack.expo.dev/@emmbyiringiro/1920d6