With react-native, I'm looking forward having a TextInput stuck with a MaterialIcons.Button within the same line.
I want the whole elements be centered horizontally but cannot achieve this with the following code:
import React from 'react';
import {
StyleSheet, TextInput, View,
} from 'react-native';
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
const WordInput = () => {
return (
<View style={styles.container}>
<View style={styles.textInputContainer}>
<TextInput
textAlign="left"
/>
</View>
<View style={styles.arrowButtonContainer}>
<MaterialIcons.Button
name="arrow-forward-ios"
/>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
flex: 1,
},
textInputContainer: {
flex: 1,
alignItems: 'flex-end',
justifyContent: 'center',
},
arrowButtonContainer: {
flex: 1,
alignItems: 'flex-start',
justifyContent: 'center',
},
});
Here is the associated expo snack link.
The problem is that when I type text inside the TextInput, the Button doesn't move at all. I would like it to dynamically shift to the right when the TextInput's width grow. The overall should be horizontally centered.
Does anyone know how I can proceed?
Thanks!
CodePudding user response:
Unfortunately <TextInput>
doesn't support any sort of "auto-growing" behaviour by default, but you could implement something yourself using a hidden <Text>
layer that has the same font styling and sizing rules as your <TextInput>
. If you then render your input value to that <Text>
element, you can measure the layout of that element and apply the measured width to your <TextInput>
component.
import { useState } from 'react';
import { StyleSheet, TextInput, View, Dimensions, Text } from 'react-native';
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
export default function App() {
const [value, setValue] = useState();
const [containerWidth, setContainerWidth] = useState(
Dimensions.get('window').width
);
const [textWidth, setTextWidth] = useState(0);
const [buttonWidth, setButtonWidth] = useState(0);
const inputWidth = Math.min(textWidth, containerWidth - buttonWidth);
return (
<View style={styles.root}>
<View
style={styles.inner}
onLayout={(e) => setContainerWidth(e.nativeEvent.layout.width)}>
<Text
style={styles.hiddenText}
onLayout={(e) => setTextWidth(e.nativeEvent.layout.width)}
numberOfLines={1}
accessibilityElementsHidden
importantForAccessibility="no-hide-decendants">
{value}
</Text>
<TextInput
textAlign="left"
placeholder="enter text"
style={[styles.input, { width: inputWidth }]}
onChangeText={setValue}
/>
<View onLayout={(e) => setButtonWidth(e.nativeEvent.layout.width)}>
<MaterialIcons.Button name="arrow-forward-ios" />
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
root: {
flex: 1,
justifyContent: 'center',
},
inner: {
flexDirection: 'row',
justifyContent: 'center',
borderWidth: 1,
borderColor: 'red',
},
input: {
borderWidth: 1,
borderColor: 'green',
minWidth: 100,
},
hiddenText: {
position: 'absolute',
top: 0,
left: 0,
opacity: 0,
},
});
Here's an expo snack example.