Text input view not render properly - ios

As a beginner on React Native, I decided to have a look at layouts. I have a component like this with a text input component and a text component.
class TextView extends Component{
render(){
return(
<View style = {{flex:1,justifyContent:'center',alignItems:'center',backgroundColor: 'pink'}}>
<TextInput style = {TextInputStyle.default}/>
<Text> Hello again! </Text>
</View>
)
}
}
After calling TextView component on root file index.ios.js the output seems like this.
As you can see only text if following the stylesheet but not the text input. Any help will be appreciated.
Edit
This is what TextInputStyle looks like
const TextInputStyle = StyleSheet.create({
default : {
color : 'darkgrey',
fontSize : 14,
backgroundColor : 'red',
height : 20,
width : 100,
}
})

First thing, you have not specified what's inside TextInputStyle.default, may be that is overriding the css style. Try to wrap TextInput in a view.
<View style = {{flex:1,justifyContent:'center',alignItems:'center',backgroundColor: 'pink'}}>
<View>
<TextInput style={{height: 40, borderColor: 'gray', borderWidth: 1, width:150}}/>
</View>
<Text> Hello again! </Text>
</View>

Related

KeyboardAvoidingViev not working on iOS with react navigation header and material bottom tabs?

You find a minimal repo here and a minimal snack available here. They both show the issue nicely with very minimal code.
I found lots of questions online about how to use KeyboardAvoidingViev with react navigation e.g.
The popular proposed solution is
keyboardVerticalOffset={headerHeight + 64}
That does not work completely for me. The 64 seems arbitrary and somehow on iOS the view shrinks after closing the keyboard.
Here is what I know so far:
It is definitely react navigation (headers and/or Material Bottom Tabs Navigator) and KeyboardAvoidingViev working together. If you remove the Material Bottom Tabs Navigator, it works.
Solutions including SafeAreaView did make it worse
Solutions with behavior={"position"} did make it worse
Solutions with +64 are not working
I found out that the solution of David Scholz works nicely, if I remove the Material Bottom Tabs Navigator.
Everything works fine on android (Samsung Galaxy 7S and emulator). From what I know, I would recommend to avoid KeyboardAvoidingViev with react navigation on android. So in fact, KeyboardAvoidingViev is also not working fully for android, but you don't need to use it.
Any help is appreciated. Thank you!
I create a wrapping component like this and pass the offset from the screen so that it gets the current context.
import React from 'react'
import { ViewStyle } from 'react-native'
import { KeyboardAvoidingView, Platform, ScrollView } from 'react-native'
type Props = {
children: any
keyboardVerticalOffset?: number
contentContainerStyle?: ViewStyle
}
export default function KeyboardWrapper({
children,
keyboardVerticalOffset,
...rest
}: Props): JSX.Element {
return (
<KeyboardAvoidingView
style={{ flex: 1 }}
keyboardVerticalOffset={keyboardVerticalOffset}
{...(Platform.OS === 'ios' ? { behavior: 'padding' } : {})}>
<ScrollView
bounces={false}
showsVerticalScrollIndicator={false}
{...rest}>
{children}
</ScrollView>
</KeyboardAvoidingView>
)
}
Usage in the screen
If you have any sticky elements like topbar or bottom bar you need to add the height so that the keyboard adds the offset correctly.
import { useHeaderHeight } from '#react-navigation/elements'
const height = useHeaderHeight()
<KeyboardWrapper
keyboardVerticalOffset={height}
contentContainerStyle={{ flex: 1 }}>
// ... your elements
</KeyboardWrapper>
This is a working demo https://snack.expo.dev/#raajnadar/fix-keyboardavoidingview-not-working
There is no need to add 64 to the headerHeight. Here is how I would solve this problem.
const flatListRef = createRef()
const [data, setData] = useState()
const headerHeight = useHeaderHeight();
<View style={{ flex: 1 }}>
<KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
keyboardVerticalOffset={headerHeight}
style={{ flex: 1 }}>
<FlatList
data={data}
ref={flatListRef}
onContentSizeChange={() =>
flatListRef.current.scrollToEnd({ animated: true })
}
onLayout={() => flatListRef.current.scrollToEnd({ animated: true })}
keyExtractor={(item) => item.id}
renderItem={({ item }) => (
<Text style={{ flex: 1, paddingVertical: 20 }}>{item.id}</Text>
)}
/>
<View style={{ flex: 1, marginBottom: 40 }}>
<TextInput
style={{
backgroundColor: '#2E2E2E',
width: '100%',
borderRadius: 18,
height: 36,
paddingLeft: 10,
paddingRight: 10,
color: '#FFFFFF',
}}
/>
</View>
</KeyboardAvoidingView>
</View>
Here is a quick and dirty snack which contains an header from a StackNavigator.

Give space between <text> components which is a child in a view component

import { Text, View, Image, StyleSheet } from 'react-native';
import * as react from 'react';
export default function TabOneScreen(){
return (
<View style={styles.container}>
<Image source = {{uri:'https://notjustdev-dummy.s3.us-east-2.amazonaws.com/avatars/elon.png'}} style={styles.image} />
my task is to give space to this text which is supposed to appear in a straight line (Elon Musk
11:11AM) using justifyContent: 'space-between' but its not having any effect instead the text are still together (Elon Musk11:11AM)
<View style={styles.row}>
<Text style={styles.name}>Elon Musk</Text>
<Text style={styles.text}>11:11 AM</Text>
</View>
<Text style={styles.text}>Boi Ice for Janet</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
container:{
flexDirection:'row',
padding:10,
},
image:{
height:60,
width:60,
borderRadius:50,
marginRight:10,
},
name:{
fontSize:20,
color:'blue',
},
row:{
flexDirection:'row',
justifyContent: 'space-between',
},
text:{
fontSize:20,
color:'blue'
}
});
You would need to use a
row:{
flex:1
// other keys
}
and/or
row:{
width:'100%'
}
so that the view (row) covers the width of the screen.

Is there a way for a TextInput to behave like a button i.e. be able to be selected (onPress)?

I am making a react native health app in which the user can select tags to describe certain symptoms they are facing. I am trying to let the user create their own tags, at the moment the user can enter tags but cannot select them. Is there a way to allow them to select text inputs?
I have already tried wrapping touchable opacity around it but when I press the text input the cursor just focuses on the word (wanting me to edit the word).
I have also tried editable = {false} this removes the ability for the user to enter a text input completely. Is there a way to allow the user to input a value once and then disable the text input (non-editable)?
Or If I used Button instead of TextInput is there a way for the user to enter the title of the button so it can act as a tag?
Here is how I have allowed users to create text inputs
addTextInput = (index) => {
let textInput = this.state.textInput;
textInput.push(
<TextInput
style={styles.textInput}
onChangeText={(text) => this.addValues(text, index)}
editable={true}
/>
);
this.setState({ textInput });
}
removeTextInput = () => {
let textInput = this.state.textInput;
let inputData = this.state.inputData;
textInput.pop();
inputData.pop();
this.setState({ textInput, inputData });
}
and this is what my current tags look like:
on the picture when the user presses the plus a new tag/TextInput is created, what I want is when the user presses it, it should be able to change color or the like.
here is the code for the plus button:
<View style={{
flexDirection: 'row',
flexGrow: '1',
flexWrap: 'wrap',
width: Responsive.width(300)
}}>
{this.state.textInput.map((value) => {
return value
})}
<TouchableWithoutFeedback onPress={() => {
this.addTextInput(this.state.textInput.length)
}}>
<Image
style={{ marginLeft: 8, width: 38, height: 38 }}
source={require('../../../assets/plusButton.png')}
/>
</TouchableWithoutFeedback>
{/* <Button title='Get Values' onPress={() => this.getValues()} /> */}
</View>
<View style={styles.row}>
<View style={{ margin: 10, top: Responsive.height(75) }}>
<Button onPress={() => this.removeTextInput()}>Remove</Button>
</View>
</View>
I had a similar problem and solved it with a TouchableOpacity over a TextInput. Using zIndex and absolute positioning you can expand the TouchableOpacity over your text input and transform it in a button, the TouchableOpacity must have a 100% opacity.
You can control with { condition && } your logic to make it behave like a button or a TextInput.
export default function App() {
const [m,setm]=React.useState(false);
return (
<View>
<TouchableOpacity style={{zIndex:10, position:'absolute', width: '100%', height: '100%', opacity:'100%'}} onPress={()=>{setm(!m)}} />
<TextInput style={{zIndex:1,backgroundColor:'#fbb',color:'#000'}} value={m}/>
</View>
);
}

Why does adding a parent View Tag in React Native change the style?

Adding a View parent breaks my styles, why is this happening? Does React Native's View tag have some default styles that I'm unaware of?
Below is the Button component as well as a screenshot with and without the View Tag.
class Button extends Component {
render() {
return (
<View>
<TouchableOpacity style={styles.buttonStyle}>
<Text style={styles.textStyle}>Hello</Text>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
textStyle: {
alignSelf: "center",
color: "#007aff",
fontSize: 16,
fontWeight: "600",
paddingTop: 10,
paddingBottom: 10
},
buttonStyle: {
flex: 1,
alignSelf: "stretch",
backgroundColor: "#fff",
borderRadius: 5,
borderWidth: 1,
borderColor: "#007aff",
marginLeft: 5,
marginRight: 5
}
});
The button is being rendered inside another component(A typical card component), if need I can provide that code as well.
Basically, your TouchableOpacity has all of your container styles, and this is going to cause the weird issue you are seeing. By defining flex:1, it means it will stretch itself to fill the area of the parent view. However, your parent view has not been flexed, so it will only fill the space that it needs to. It will however put your text component in however it seems fit, hence the weird result you are getting.
To debug this, I often will set backgroundColor: 'red', to see what flexbox is doing. In your case, i don't see the need for a parent view ? TouchableOpacity is simply an extension of view, so you should be able to do all your styling in it. If you are wanting to add a view though, i'd suggest wrapping it with your Touchable - otherwise you have the risk of messing up your onPresss. Something like
render() {
return (
<View style = {{height: 100, shadowColor: 'black', shadowRadius: 3}}> //RANDOM CARD CODE
<TouchableOpacity style={styles.buttonStyle}>
<View> //ANY STYLES HERE
<Text style={styles.textStyle}>Hello</Text>
</View>
</TouchableOpacity>
</View>
)};

Why isn't zIndex working in React Native?

I've been trying to use the property zIndex on a ScrollView but it doesn't seem to be working. When I apply zIndex it looks like this:
As you can see, the ScrollView is being blocked by the input. I want the effect of having the ScrollView completely cover the other input when the suggestions come up, with zIndex. Here's what I have right now:
<View>
<Input
value={this.state.inputValue}
style={styles._input}
inputStyle={styles._text}
onChangeText={this.handleChangeText}
{...this.props}
/>
<View style={styles._spacing}></View>
{predictions.length ?
<ScrollView
style={styles._scroll}
>
{predictions.map(this.renderPrediction)}
</ScrollView>
: null}
</View>
Note that Input is a separate component that renders a specific TextInput. Also, this.renderPrediction returns this:
<Text
style={styles._text}
key={index}
onPress={this.handlePredictionPress.bind(null, prediction.description)}
>
{prediction.description}
</Text>
And finally here are my styles:
const styles = EStyleSheet.create({
input: StyleSheet.flatten([inputStyle]),
text: {
fontSize: 15,
},
spacing: {
height: 10
},
scroll: {
position: "absolute",
zIndex: 10,
width: "80%",
top: 50,
backgroundColor: "white"
}
});
Why isn't my zIndex attempt working and how can I get it to work as desired?
According to your image it looks like the zIndex is working as expected, the ScrollView is over the input. But the white background didn't catch.
Use contentContainerStyle for the background color behind the items.
<ScrollView style={styles._scroll} contentContainerStyle={styles._contentContainer} >
...
contentContainer: {backgroundColor: "white"}

Resources