Currently I'm learning React Native with the help of a book in which is explained how to build a to do app. However I can't continue because of this error/bug. This is happening in IOS, not sure if this also happens on Android as I haven't set up my Android emulator just jet.
My <View> container has two <TextInputs>, working fine.
When I wrap both inputs into views, they simply 'disappear'.
Here is my component NoteScreen.js:
import React, {
Component,
StyleSheet,
TextInput,
View
} from 'react-native';
export default class NoteScreen extends Component {
render() {
return (
<View style={styles.container}>
<View style={styles.inputContainer}>
<TextInput
ref="title"
autoFocus={true}
autoCapitalize="sentences"
placeholder="Untitled"
style={styles.title}
onEndEditing={(text) => {this.refs.body.focus()}}
/>
</View>
<View style={styles.inputContainer}>
<TextInput
ref="body"
multiline={true}
placeholder="Start typing"
style={styles.body}
textAlignVertical="top"
underlineColorAndroid="transparent"
/>
</View>
</View>
);
}
}
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
marginTop: 64
},
textInput: {
color: '#ffffff',
flex: 1,
width: 60,
height: 60,
fontSize: 16
},
inputContainer: {
borderBottomColor: '#9E7CE3',
borderBottomWidth: 1,
flex: 1,
flexDirection: 'row',
marginBottom: 10
},
title: {
fontFamily: 'Overpass-Bold',
height: 40
},
body: {
fontFamily: 'Overpass-Bold',
flex: 1
}
});
I did some research and noticed some weird things;
Both of my inputs have a width and a height
The inputs vanish also if they don't have any styles applied to them
This only happens with text inputs, normal text just renders.
Some insight would be great, I'm thinking this is a bug, or I am just overlooking something..
I tried your example (on android), and with exact code you provided, screen is completely empty. Without styles on text input, they are not showing, and you've set styles.title and styles.body to your TextInput components -> in styles.title and styles.body you don't have (both) width and height. So what you can do is:
Add width to your title and body styles
or
Add styles to text input in array and apply both styles for textInput and for title/body like this: style={[styles.textInput, styles.title]} and style={[styles.textInput, styles.body]}
Here is working code for both suggestions i gave you:
import React, {
AppRegistry,
Component,
StyleSheet,
TextInput,
View
} from 'react-native';
export default class NoteScreen extends Component {
render() {
return (
<View style={styles.container}>
<View style={styles.inputContainer}>
<TextInput
ref="title"
autoFocus={true}
autoCapitalize="sentences"
placeholder="Untitled"
style={styles.title}
onEndEditing={(text) => {this.refs.body.focus()}}
/>
</View>
<View style={styles.inputContainer}>
<TextInput
ref="body"
multiline={true}
placeholder="Start typing"
style={[styles.textInput, styles.body]}
textAlignVertical="top"
underlineColorAndroid="transparent"
/>
</View>
</View>
);
}
}
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
marginTop: 64
},
textInput: {
color: '#ffffff',
flex: 1,
width: 60,
height: 60,
fontSize: 16
},
inputContainer: {
borderBottomColor: '#9E7CE3',
borderBottomWidth: 1,
flex: 1,
flexDirection: 'row',
marginBottom: 10
},
title: {
fontFamily: 'Overpass-Bold',
height: 40,
width: 40
},
body: {
fontFamily: 'Overpass-Bold',
flex: 1
}
});
I believe we are reading the same book, becausee I had the same problem.
I solved it by removing the alignItems: 'center' in the container style and adding flex: 1 to the inputContainer style. It still doesn't look like the book sample, but at least the fields are now visible.
Here's what my code looks like:
import React, { StyleSheet, Text, TextInput, View } from "react-native";
import dismissKeyboard from "dismissKeyboard";
export default class NoteScreen extends React.Component {
render() {
handleTitleEditingEnd = (text) => { this.refs.body.focus(); };
return (
<View style={styles.container}>
<View style={styles.inputContainer}>
<TextInput
ref="title"
placeholder="Untitled"
style={[styles.textInput, styles.title]}
onEndEditing={handleTitleEditingEnd}
returnKeyType="next"
/>
</View>
<View style={styles.inputContainer}>
<TextInput
ref="body"
multiline={true}
placeholder="Start typing"
style={[styles.textInput, styles.body]}
/>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
// alignItems: "center",
marginTop: 64
},
inputContainer: {
borderBottomColor: "#9E7CE3",
borderBottomWidth: 1,
flexDirection: "row",
marginBottom: 10,
flex: 1,
},
textInput: {
flex: 1,
fontSize: 16,
},
title: {
height: 40,
},
body: {
flex: 1,
}
});
If your <Text> don't have height in your <View>, try removing flex : 1 from your container.
I solved it with code below:
import React, {
StyleSheet,
TextInput,
View
} from 'react-native';
export default class NoteScreen extends React.Component {
render() {
return (
<View style={styles.container}>
<View style={styles.inputContainer}>
<TextInput ref="title" autoFocus={true} autoCapitalize="sentences" placeholder="Untitled" style={[styles.textInput, styles.title]} onEndEditing={(text) => {this.refs.body.focus()} }/>
</View>
<View style={styles.inputContainer}>
<TextInput ref="body" multiline={true} placeholder="Start typing" style={[styles.textInput, styles.body]}/>
</View>
</View>
);
}
}
var styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
marginTop: 64
},
title: {
height: 40
},
body: {
height: 160,
flex: 1
},
inputContainer: {
borderBottomColor: '#9E7CE3',
borderBottomWidth: 1,
flexDirection: 'row',
marginBottom: 10
},
textInput: {
flex: 1,
fontSize: 16,
width: 300,
}
});
Related
One of my React Native screens needs to have a TouchableOpacity at the bottom of the screen. I've tried setting position: "absolute" and bottom: 0, however, this just causes the element to be a few hundred pixels below the screen. How can I make my TouchableOpacity be at the bottom of the screen all the time?
<View style={styles.mainView}>
<View style={{ position: "relative" }}>
<TouchableOpacity style={styles.cartView}>
<Text style={styles.cartText}>View cart</Text>
</ViewTouchableOpacity
</View>
}
/>
</View>
//styles
const styles = StyleSheet.create({
mainView: {
// devDims are the device dimensions
minHeight: devDims.height,
minWidth: devDims.width,
backgroundColor: "white",
paddingLeft: 10,
paddingRight: 10,
paddingTop: 10,
},
cartView: {
justifyContent: "center",
alignItems: "center",
maxHeight: 50,
minWidth: "100%",
alignSelf: "center",
marginTop: 50,
padding: 10,
borderRadius: 20,
},
cartText: {
fontFamily: "semi",
fontSize: 22,
},
});
We could handle this without absolute positioning using flex alone.
Add flex:1 to the parent view and to the view that wraps the sticky bottom. Then, add flex: 2 to the view that wraps the other content.
Here is a minimal generic component that lets you add a sticky bottom component.
const MainScreen = ({bottom, children}) => {
return <View style={{flex: 1, backgroundColor: 'red'}}>
<View style={{flex: 2, backgroundColor: 'green'}}>
{children}
</View>
<View style={{flex: 1, backgroundColor: 'yellow'}}>
{bottom}
</View>
</View>
}
export default function App() {
return <MainScreen bottom={
<TouchableOpacity style={styles.cartView}>
<Text style={styles.cartText}>View cart</Text>
</TouchableOpacity>}>
</MainScreen>
}
The result looks as follows:
However, we can use absolute positioning as well. You are just missing the flex: 1 for the parent view.
export default function App() {
return <View style={styles.mainView}>
<View style={{ position: "absolute", bottom: 0 }}>
<TouchableOpacity style={styles.cartView}>
<Text style={styles.cartText}>View cart</Text>
</TouchableOpacity>
</View>
</View>
}
const styles = StyleSheet.create({
mainView: {
flex: 1,
// devDims are the device dimensions
minHeight: devDims.height,
minWidth: devDims.width,
backgroundColor: "red",
paddingLeft: 10,
paddingRight: 10,
paddingTop: 10,
},
cartView: {
justifyContent: "center",
alignItems: "center",
maxHeight: 50,
minWidth: "100%",
backgroundColor: "yellow",
alignSelf: "center",
marginTop: 50,
padding: 10,
borderRadius: 20,
},
cartText: {
fontFamily: "semi",
fontSize: 22,
},
});
The result is as follows:
if you are using position as absolute then your view must be last view before last closed view tag
When you have declared any view at bottom of the screen then you should be do like this
import {View, SafeAreaView} from 'react-native';
<SafeAreaView style={{flex:1}}>
<View style={{flex:1}}>
<!---Anything extra views---!>
<View style={{bottom:0,position:'absolute',start:0,end:0}}> !-- you're bottom view
<TouchableOpacity style={styles.cartView}>
<Text style={styles.cartText}>View cart</Text>
</ViewTouchableOpacity
</View>
</View>
</SafeAreaView >
I have a react native project I am building. On the home screen I want to render a list of components called PropertyTile with some text in between just for testing. With my current code, it is rendering the first instance of the PropertyTile, but not rendering anything after that. It is extremely wierd and I can not find a solution to this issue for some reason. Why would it only show the first PropertyTile without rendering anything else.
Code:
import React from 'react'
import { View, Text, StyleSheet } from 'react-native'
import PropertyTile from '../components/PropertyTile.js'
const HomeScreen = () => {
return (
<View style={styles.screenContainer}>
<PropertyTile/>
<Text>Home Screen: Shows currentl asdfasdf!</Text>
<Text>Home Screen: Shows currentl fe!</Text>
<PropertyTile />
</View>
)
}
const styles = StyleSheet.create({
header: {
fontSize: 22
},
screenContainer: {
display: 'flex',
flexDirection: 'column'
}
})
export default HomeScreen
current screen rendering
PropertyTile Code:
import React from 'react'
import { Dimensions } from 'react-native'
import { View, Text, StyleSheet, Image } from 'react-native'
export default function PropertyTile() {
let deviceWidth = Dimensions.get('window').width - 16
var aspectHeight = (deviceWidth / 1.78) + 1
return (
<View style={styles.container}>
<View style={[styles.imageContainer,{height: aspectHeight}]}>
<Image style={styles.mainImage} source={require('../../assets/luxury-home-1.jpeg')}/>
</View>
<View style={styles.contentContainer}>
<View style={styles.priceContainer}>
<Text style={styles.price}>$ 1,259,999</Text>
<Text style={styles.status}>For Sale</Text>
</View>
<View style={styles.addressContainer}>
<Text style={styles.address}>23 Lowlette Lane.</Text>
<Text style={styles.address}>Mission Viejo, CA 92692</Text>
</View>
<View style={styles.separator}></View>
<View style={styles.details}>
<Text style={styles.summary}>6 Beds | 6 Baths | 10,000 Sqft. | 1.3 acre Lot</Text>
<Text style={styles.homeType}>Single Family Residence</Text>
</View>
<View style={styles.separator}></View>
<View style={styles.details}>
<View style={styles.metricContainer}>
<Text style={styles.metricName}>Net Operating Income (Monthly): </Text>
<Text style={styles.metricValue}>$5,789</Text>
</View>
<View style={styles.metricContainer}>
<Text style={styles.metricName}>Cash on Cash Return: </Text>
<Text style={styles.metricValue}>2.45%</Text>
</View>
<View style={styles.metricContainer}>
<Text style={styles.metricName}>Return on Initial Investment: </Text>
<Text style={styles.metricValue}>9.97%</Text>
</View>
</View>
<View style={styles.disclaimerContainer}>
<Text style={styles.disclaimer}>*** 30 year fixed, 20% down, 3.14% interest rate | $3,443 rent ***</Text>
</View>
</View>
</View>
)
}
const styles = StyleSheet.create({
container: {
height: '100%',
paddingTop: 8,
paddingHorizontal: 8,
borderRadius: 6,
overflow: 'hidden'
},
imageContainer: {
width: '100%',
borderTopLeftRadius: 6,
borderTopRightRadius: 6,
overflow: 'hidden'
},
mainImage: {
width: '100%',
height: '100%'
},
contentContainer: {
width: '100%',
backgroundColor: '#D3D3D3',
borderBottomLeftRadius: 6,
borderBottomRightRadius: 6,
overflow: 'hidden',
paddingHorizontal: 8
},
priceContainer: {
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingTop: 8,
},
price: {
fontWeight: 'bold',
fontSize: 24
},
addressContainer: {
display: 'flex',
marginTop: 8
},
address: {
fontSize: 14
},
separator: {
marginHorizontal: '3%',
marginVertical: 8,
height: 2,
width: '94%',
backgroundColor: 'grey'
},
homeType: {
marginTop: 4,
},
metricContainer: {
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
marginTop: 4
},
metricValue: {
fontWeight: 'bold'
},
disclaimerContainer: {
display: 'flex',
flexDirection: 'row',
marginVertical: 8,
width: '100%',
justifyContent: 'center',
},
disclaimer: {
fontSize: 12,
}
})
I believe that your aspectHeight variable in your PropertyTile component is preventing the second instance from appearing. aspectHeight is applying a height that spans the height of the screen, pushing the other instances out of view.
You can try wrapping your HomeScreen in a ScrollView so you can see all of the elements that render below the screen's window, like this:
import React from 'react'
import { View, Text, StyleSheet, ScrollView } from 'react-native'
import PropertyTile from '../components/PropertyTile.js'
const HomeScreen = () => {
return (
<ScrollView>
<View style={styles.screenContainer}>
<PropertyTile/>
<Text>Home Screen: Shows currentl asdfasdf!</Text>
<Text>Home Screen: Shows currentl fe!</Text>
<PropertyTile />
</View>
</ScrollView>
)
}
I'm new to react native, and I'm trying to put a horizontal scrollview on my screen.
I've tried to put <ScrollView horizontal={true}> but it's not working at all, I want the blue box scrollable.
here' the image of my screen :
and this for my component code :
import React from 'react';
import {View, StyleSheet, Text, Image, ScrollView} from 'react-native';
export default function Body() {
return (
<View>
<View style={styles.jadwal}>
<ScrollView horizontal={true}>
<View style={styles.box}>
<Text style={styles.title}>Math</Text>
<View style={styles.wrap}>
<View style={styles.alert}>
<Text style={styles.pr}>3 Homework</Text>
<Image
style={styles.img}
source={require('../assets/math.png')}
/>
</View>
</View>
</View>
<View style={styles.box}>
<Text style={styles.title}>Biology</Text>
<View style={styles.wrap}>
<View style={styles.alert}>
<Text style={styles.pr}>10 Homework</Text>
<Image
style={styles.img}
source={require('../assets/math.png')}
/>
</View>
</View>
</View>
</ScrollView>
</View>
</View>
);
}
const styles = StyleSheet.create({
jadwal: {
marginLeft: 10,
flexDirection: 'row',
justifyContent: 'flex-start',
position: 'absolute',
},
box: {
height: 100,
width: 230,
borderRadius: 10,
backgroundColor: '#327fe3',
marginLeft: 10,
},
alert: {
height: 20,
marginLeft: 15,
width: 80,
borderRadius: 10,
backgroundColor: '#7CD5FF',
},
title: {
marginTop: 20,
marginLeft: 20,
fontFamily: 'MontserratSemiBold',
fontSize: 15,
color: '#fff',
},
pr: {
marginLeft: 14,
fontSize: 8,
color: '#fff',
marginTop: 4,
justifyContent: 'flex-start',
fontFamily: 'MontserratLight',
},
wrap: {
marginTop: 5,
},
img: {
height: 50,
width: 50,
marginLeft: 140,
marginTop: -35,
},
});
is there anything wrong ?, did I put the <ScrollView> on wrong position ?
Thanks for reading this, and sorry for my bad english.
There's one error of font-family cause, this font is not installed in my laptop.
Overall your scroll view is working fine.
Note: scroll view is scrolling area is in between the opening and closing tag of scroll.
I am trying to build a react native application with the expo, First I try to build this application with my chrome web browser, it was worked without any issue after that I try to test the application with my android device and I'm getting an exception - "Text strings must be rendered within a <Text> component" HomeScreen.js files. I have no idea why this happened. My code as follows,
/*This is an Example of Grid View in React Native*/
// import * as React from "react";
import React from 'react';
import { Image, FlatList, StyleSheet, View, Text, TouchableOpacity, TextInput } from 'react-native';
import { COLORS } from '../../asserts/Colors/Colors';
import { CATEGORIES } from '../../asserts/mocks/itemListData';
import CategoryGridTitle from '../components/HomeGridTile';
import { HeaderButtons, Item } from 'react-navigation-header-buttons';
import { HeaderButton } from '../components/HeaderButton';
import HomeScreenButton from '../components/HomeScreenButton';
//import all the components we will need
const renderTopBarItems = (topBarItems) => {
return (
<TouchableOpacity
style={styles.topBar}>
<Text style={styles.textStyle}> {topBarItems.item.category} </Text>
</TouchableOpacity>
)
}
const HomeScreen = props => {
const renderGridItem = (itemData) => {
return <CategoryGridTitle
title={itemData.item.title}
image={itemData.item.image}
onSelect={() => {
props.navigation.navigate({
routeName: 'PaymentHandlerScreen',
params: {
categoryId: itemData.item.id
}
});
}} />;
}
// const [images, setImages] = React.useState(picsumImages);
return (
<View style={styles.mainBody}>
<View style={styles.searchContainer}>
<TextInput
placeholder='Search'
style={styles.formField}
placeholderTextColor={'#888888'}
/>
<TouchableOpacity onPress={() => props.navigation.navigate('BarCodeScannerScreen')}
style={styles.saveFormField}>
<Image
source={require('../../../images/barcode.png')}
style={{
width: '100%',
height: '30%',
resizeMode: 'contain',
alignContent: 'center',
}}
/> </TouchableOpacity>
</View>
<View style={styles.tabBar}>
<FlatList
horizontal
pagingEnabled={true}
showsHorizontalScrollIndicator={false}
keyExtractor={(item, index) => item.id}
data={CATEGORIES}
renderItem={renderTopBarItems} />
</View>
<FlatList
keyExtractor={(item, index) => item.id}
data={CATEGORIES}
renderItem={renderGridItem}
numColumns={3} />
<HomeScreenButton style={styles.buttonView} />
</View>
);
};
HomeScreen.navigationOptions = navigationData => {
return {
headerTitle: 'Tickets',
headerRight: (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title='profile'
iconName='ios-star'
onPress={() => {
console.log('profile clicked');
}} />
<Item
title='more'
iconName='md-more'
onPress={() => {
console.log('more clicked');
}} />
</HeaderButtons>
)
};
};
export default HomeScreen;
const styles = StyleSheet.create({
mainBody: {
flex: 1,
justifyContent: 'center',
backgroundColor: COLORS.background,
paddingTop: '3%',
},
searchContainer: {
flex: 1,
flexDirection: 'row',
},
tabBar: {
paddingBottom: '3%',
},
topBar: {
width: 150,
borderWidth: 1,
borderRadius: 20,
borderColor: COLORS.primary_blue,
padding: '5%',
marginLeft: '5%',
},
textStyle: {
color: COLORS.primary_blue,
textAlign: 'center',
fontWeight: 'bold',
fontSize: 14,
},
formField: {
flex: 4,
borderWidth: 1,
padding: '4%',
marginLeft: '2%',
borderRadius: 10,
borderColor: COLORS.gray,
backgroundColor: COLORS.gray,
fontSize: 15,
height: '35%',
},
saveFormField: {
flex: 0.5,
justifyContent: 'space-between',
alignItems: 'center',
margin: 10,
},
buttonView: {
position: 'absolute',
bottom: 0,
left: 0,
},
});
Thank you.
I ran into this error a couple of times. RN doesn't like extra spaces in tags. try removing the spaces before and after {topBarItems.item.category}
<Text style={styles.textStyle}>{topBarItems.item.category}</Text>
I'm trying to create a menu for my application in React-Native which should have multiple icons in the below way
The icons should be in the same row and wrapped so that if screen is bigger more icons will be on the same row.
My current code is as follows
import React from 'react';
import { StyleSheet, View } from 'react-native';
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<View style={styles.box}></View>
<View style={styles.box}></View>
<View style={styles.box}></View>
<View style={styles.box}></View>
<View style={styles.box}></View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'space-evenly',
flexDirection: 'row',
flexWrap: 'wrap',
paddingTop: 40
},
box: {
width: 100,
height: 100,
backgroundColor: 'aqua',
margin: 10,
}
});
The current output is as below
The children count may change in the future but i need to have spacing on the sides, using flex-start will give the below output which is wrong.i want to have spacing in both sides as well.
How do i align it to left and have the items with even space around as the image above ?
for Box use Dimensions, Based on screen width divide box width
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'flex-start',
flexDirection: 'row',
flexWrap: 'wrap',
paddingTop: 40
},
box: {
width: (Dimensions.get('window').width / 3) - 20, /* minus some value for adjust the gap between boxes */
height: 100,
backgroundColor: 'aqua',
margin: 10,
}
});
One option is to add extra 'fake' boxes which will fill the available space in last row:
<View style={styles.box}></View>
<View style={styles.box}></View>
<View style={styles.box}></View>
<View style={styles.box}></View>
<View style={styles.box}></View>
<View style={[styles.box, styles.boxFake]}></View>
<View style={[styles.box, styles.boxFake]}></View>
<View style={[styles.box, styles.boxFake]}></View>
<View style={[styles.box, styles.boxFake]}></View>
<View style={[styles.box, styles.boxFake]}></View>
// reset all styles like backgroundColor, border, etc.
const styles = StyleSheet.create({
boxFake: {
backgroundColor: 'transparent'
}
});
You can easy calculate the number of necessary 'fake' boxes by the formula:
fakeBoxes = boxesPerRow - totalBoxes % boxesPerRow
I took a different approach by using another view as a wrapper and doing the calculation of its width, this is easier to decide the column widths.
The only problem is that we should know the width of the item, wont be a problem in my case.
The code will be as below.
import React from 'react';
import { StyleSheet, View, ScrollView } from 'react-native';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
width: 110
};
}
render() {
//width of child is 110
const width = `${100 / parseInt(this.state.width / 110)}%`;
return (
<ScrollView>
<View style={styles.container} onLayout={this.onLayout.bind(this)}>
<View style={[styles.wrapper, { width: width }]}>
<View style={styles.box}></View>
</View>
<View style={[styles.wrapper, { width: width }]}>
<View style={styles.box}></View>
</View>
<View style={[styles.wrapper, { width: width }]}>
<View style={styles.box}></View>
</View>
<View style={[styles.wrapper, { width: width }]}>
<View style={styles.box}></View>
</View>
<View style={[styles.wrapper, { width: width }]}>
<View style={styles.box}></View>
</View>
</View>
</ScrollView>
);
}
onLayout(e) {
if (this.state.width !== e.nativeEvent.layout.width) {
this.setState({
width: e.nativeEvent.layout.width
})
}
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'flex-start',
justifyContent: 'flex-start',
flexDirection: 'row',
flexWrap: 'wrap',
paddingTop: 40
},
box: {
width: 100,
height: 100,
backgroundColor: 'green',
},
wrapper: {
marginVertical: 10, alignItems: 'center'
}
});