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 >
Related
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 am trying to code one dynamic flatlist modal gallery in react native but I do not know where to start, I have added gif file for the output I am looking. It will be very helpful if any body could share the code or give some idea how to go about.
Thanking in advance.
Working Example: Expo Snack
Here is the working code:
import React, { useState } from 'react';
import {
Text,
View,
StyleSheet,
FlatList,
TouchableOpacity,
Modal,
Alert,
} from 'react-native';
import Constants from 'expo-constants';
let img = ['one', 'two', 'three', 'four', 'five', 'six', 'seven'];
export default function App() {
const [selected, setSelected] = useState(null);
return (
<View style={styles.container}>
<FlatList
keyExtractor={(item) => item}
numColumns={3}
data={img}
renderItem={({ item, index }) => (
<TouchableOpacity onPress={() => setSelected(index)}>
<View style={styles.thumb}>
<Text>{item}</Text>
</View>
</TouchableOpacity>
)}
/>
<Modal
animationType="slide"
transparent={true}
visible={selected !== null}
onRequestClose={() => {
this.setSelected(null);
}}>
<View style={styles.preview}>
<TouchableOpacity onPress={() => setSelected(null)}>
<View style={styles.button}>
<Text>{'X'}</Text>
</View>
</TouchableOpacity>
<View
style={{
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'rgba(00, 00, 255, 0.4)',
flex: 1,
marginVertical: 50,
marginHorizontal: 10,
}}>
<Text>{img[selected]}</Text>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
position: 'fixed',
left: 0,
right: 0,
}}>
<TouchableOpacity
onPress={() => {
if (selected > 0) {
setSelected(selected - 1);
}
}}>
<View
style={[
styles.button,
{ width: 30, height: 30, borderRadius: 15 },
]}>
<Text>{'<'}</Text>
</View>
</TouchableOpacity>
<TouchableOpacity
onPress={() => {
if (selected < img.length - 1) {
setSelected(selected + 1);
}
}}>
<View
style={[
styles.button,
{ width: 30, height: 30, borderRadius: 15 },
]}>
<Text>{'>'}</Text>
</View>
</TouchableOpacity>
</View>
</View>
</View>
</Modal>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
thumb: {
backgroundColor: 'red',
width: 100,
height: 100,
margin: 5,
justifyContent: 'center',
alignItems: 'center',
},
preview: {
borderRadius: 10,
position: 'absolute',
bottom: 20,
top: 20,
left: 10,
right: 10,
backgroundColor: 'rgba(52, 52, 52, 0.8)',
},
button: {
width: 40,
height: 40,
justifyContent: 'center',
alignItems: 'center',
borderRadius: 20,
backgroundColor: 'rgba(255, 255, 255, 0.5)',
margin: 10,
},
});
Put your image urls in to an array.
When pressed on the image, set the selected image index and set the modal visible.
Show the image in the modal from the array using the selected index.
Left - Right arrows can increase/decrease the selected image index so the image changes.
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 have a list that shows results matching the user's input. The onPress of the touchableOpacity is not working in this list. This list is positioned absolutely and positioned below its parent view (positioned relative). The only time I can get the onPress to work is when I remove the top:48 style from list and the onPress works for the single element which is directly onTop of the parent.
export default function IndoorForm(props) {
return (
<View style={styles.container}>
<View style={styles.parent}>
<Autocomplete
style={styles.autocomplete}
autoCompleteValues={autoCompleteValues}
selectedLocation={props.getDestination}
></Autocomplete>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignSelf: "center",
position: "absolute",
top: Platform.OS === "android" ? 25 + 48 : 0 + 48,
width: Dimensions.get("window").width - 30,
zIndex: 500
},
parent: {
position: "relative",
flex: 1,
borderWidth: 2,
borderColor: "#AA2B45",
height: 48,
backgroundColor: "#fff",
flexDirection: "row",
alignItems: "center",
paddingLeft: 16,
paddingRight: 16,
justifyContent: "space-between"
}
}
export default function AutoComplete(props: AutoCompleteProps) {
const { autoCompleteValues } = props;
return (
<View style={styles.container}>
<FlatList
data={autoCompleteValues}
renderItem={({ item }: { item: POI }) => (
<TouchableOpacity onPress={() => console.log("Haal")} key={item.displayName} style={styles.list}>
<Text style={styles.text}>{item.displayName}</Text>
<Entypo name={"chevron-thin-right"} size={24} color={"#454F63"} />
</TouchableOpacity>
)}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
position: "absolute",
flex: 1,
width: Dimensions.get("window").width - 30,
top: 48,
borderWidth: 2,
borderColor: "#F7F7FA",
backgroundColor: "#F7F7FA",
zIndex: 999
},
list: {
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
paddingTop: 15,
paddingLeft: 10,
paddingBottom: 10,
borderBottomColor: "rgba(120, 132, 158, 0.08)",
borderBottomWidth: 1.4,
zIndex: 999
}
}
I know you solved your issue already, but you can use this magical library react-native-gesture-handler, import your Touchables from there and they don't care about being inside the parent views. You can touch them regardless.
Resolved this by dynamically adjusting the container height so that the touchableOpacity is within the container. The issue was I positioned the list outside of the parent (as intended by styling) but for onPress to work it has to be inside the parent.
let autocompleteHeight = autoCompleteValues.length * 65
<View style={[styles.container, {height: autocompleteHeight}]}>
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'
}
});