Progress bar UI custom design in React Native - javascript

I'm quite new to react native and javascript and I have to make this type of progress bar with the four categories.
Can anyone help or suggest to me how can I achieve this UI in react native for android and iOS on both platforms?
The expected output screenshot is attached below:
However, I don't need the user interaction or progress animation, I just have to show the fix progress in percentage.

Here's an approximation of your component built in React Native, you'll need to add react-native-linear-gradient to your dependencies beforehand
I have also created a demo on Expo (you should test it on the target device) that uses expo's version of the linear gradient library. https://snack.expo.dev/#sabihi/milestone-progressbar
import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
import LinearGradient from 'react-native-linear-gradient';
export default function App() {
return (
<View style={styles.container}>
<View style={styles.progressLabels}>
<Text style={styles.progressLabel}>Beginner</Text>
<View style={styles.progressLabel}></View>
<Text style={styles.progressLabel}>Amateur</Text>
<View style={styles.progressLabel}></View>
<Text style={styles.progressLabel}>Elite</Text>
<View style={styles.progressLabel}></View>
<Text style={styles.progressLabel}>Master</Text>
</View>
<View style={styles.progressContainer}>
<LinearGradient colors={["rgb(7, 14, 60)", "rgb(86, 90, 106)"]} style={styles.progress}/>
<View style={styles.milestonesContainer}>
<View style={styles.milestone}/><View style={styles.milestone}/><View style={styles.milestone}/>
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
// paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
progressLabels: {
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
width: "100%",
marginBottom: 10,
},
progressLabel: {
fontSize: 12,
fontWeight: 'bold',
fontFamily: "sans-serif",
width: "14.3%",
textAlign: "center"
},
progressContainer: {
position: "relative",
height: 100
},
progress: {
marginLeft: "5%",
marginTop: 5,
width: "90%",
height: 30,
// backgroundColor: "rgb(7, 14, 60)",
borderRadius: 15
},
milestonesContainer: {
marginLeft: "5%",
position: "absolute",
width: "100%",
display: "flex",
flexDirection: "row"
},
milestone: {
height: 40,
width: "30%",
// backgroundColor: "white",
borderColor: "rgb(7, 14, 60)",
borderLeftWidth: 1,
borderRightWidth: 1,
}
});

Related

Absolute positioning causes React Native component to go off screen

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 >

How to create the attached UI(grid with different squares) in react native?

Here's the UI I want to create:
How do I create the above UI in react native and have it scale on all devices? I tried using flexbox but I couldn't get the boxes to be squares. The code below is using fixed width and height in which I was thinking I could scale them in proportion to the flex container they're in but I don't know how that would be implemented and I haven't found anything similar so far.
return (
<View>
<View style={styles.cardContainer}>
<View style={styles.leftSection}></View>
<View style={styles.rightSection}>
<View style={styles.section}>
<View style={styles.smallSquare}></View>
<View style={styles.smallSquare}></View>
<View style={styles.smallSquare}></View>
</View>
<View style={styles.section}>
<View style={styles.smallSquare}></View>
<View style={styles.smallSquare}></View>
<View style={styles.smallSquare}></View>
</View>
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
cardContainer: {
height: 152,
flexDirection: "row",
borderRadius: 26,
marginTop: 8,
padding: 5,
backgroundColor: "lightgrey",
justifyContent: "space-between",
},
leftSection: {
flex: 3,
backgroundColor: "teal",
borderRadius: 23,
},
rightSection: {
flex: 5,
marginHorizontal: 10,
},
largeSquare: {
width: "100%",
height: "100%",
borderRadius: 23,
},
section: {
flex: 1,
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
},
smallSquare: {
backgroundColor: "teal",
borderRadius: 14,
width: 62,
height: 62,
},
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.5.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.5.0/umd/react-dom.production.min.js"></script>
I just made the code for you. Just copy and play with it.
import React from "react";
import { FlatList, StyleSheet, Text, View } from "react-native";
const DATA = [1, 2, 3, 4, 5, 6];
const renderItem = ({ item }) => {
return <View style={styles.item}></View>;
};
function App() {
return (
<View style={styles.app}>
<View style={styles.letConatiner} />
<View style={{ flex: 2.5 }}>
<FlatList
data={DATA}
renderItem={renderItem}
keyExtractor={(item) => item}
numColumns={3}
/>
</View>
</View>
);
}
const styles = StyleSheet.create({
app: {
flex: 1,
flexDirection: "row",
flexWrap: "wrap",
backgroundColor: "lightgrey",
padding: 10
},
letConatiner: {
height: "62%",
flex: 1,
backgroundColor: "teal",
borderRadius: 15,
marginTop: 10
},
item: {
flex: 1,
padding: 50,
backgroundColor: "green",
margin: 10,
borderRadius: 15,
height: "50%"
}
});
export default App;
Not the perfect solution I was hoping to find but it's a start. Maybe someone can build on it.
import { StatusBar } from "expo-status-bar";
import {
StyleSheet,
View,
Text,
Image,
Pressable,
FlatList,
Dimensions,
} from "react-native";
const windowWidth = Dimensions.get("window").width;
const windowHeight = Dimensions.get("window").height;
export default function HomeScreen() {
return (
<View style={styles.homeScreen}>
<View style={styles.cardOuter}>
<View style={styles.cardContainer}>
<View style={styles.leftSection}>
<View style={styles.bigThumbnail}></View>
</View>
<View style={styles.rightSection}>
<View style={styles.section}>
<View style={styles.smallThumbnail}></View>
<View style={styles.smallThumbnail}></View>
<View style={styles.smallThumbnail}></View>
</View>
<View style={styles.section}>
<View style={styles.smallThumbnail}></View>
<View style={styles.smallThumbnail}></View>
<View style={styles.smallThumbnail}></View>
</View>
</View>
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
homeScreen: {
backgroundColor: "black",
flex: 1,
paddingHorizontal: 10,
},
cardOuter: {
paddingVertical: 4,
backgroundColor: "#eee",
borderRadius: 26,
},
cardContainer: {
height: windowHeight / 5.4,
flexDirection: "row",
borderRadius: 26,
paddingHorizontal: 10,
justifyContent: "center",
alignItems: "center",
},
leftSection: {
marginRight: 0,
},
rightSection: {
flex: 5,
},
bigThumbnail: {
backgroundColor: "teal",
borderRadius: 26,
width: windowWidth / 3,
height: "96%",
},
smallThumbnail: {
backgroundColor: "teal",
borderRadius: 14,
width: windowWidth / 6,
height: windowWidth / 6,
},
section: {
flex: 1,
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
paddingLeft: 10,
marginVertical: 0,
},
});

No element after component is rendering on the screen React Native

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>
)
}

React Native ScrollView Horizontal not working

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.

React Native TouchableOpacity not working with position absolute

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}]}>

Categories