Task at hand:
What I've taken a lot at so far:
Pie chart from [https://github.com/JesperLekland/react-native-svg-charts-examples][2]
Here I divided the entire pie into 50 units of 1 value, inorder to get the Split-bar effect. I can pass the color according to the image shown above.
But how can I add the inner lines(red and green) and the data inside?
Any help would be appreciated!
So the approach I would take is to make the outer ring a PieChart (like you have done), but to make the inner circle a ProgressCircle (https://github.com/JesperLekland/react-native-svg-charts#progresscircle) as this component naturally looks like the inner circle in the picture. You can change its backgroundColor prop to red and its progressColor prop to green.
import {PieChart, ProgressCircle} from 'react-native-svg-charts';
import Svg, {Text as SvgText, ForeignObject} from 'react-native-svg';
import Icon from 'react-native-vector-icons/FontAwesome5';
// ...
class CustomPieChart extends React.PureComponent {
render() {
const data = Array.apply(null, Array(50)).map(Number.prototype.valueOf, 1);
// Change to whatever your fill function looks like...
const getFill = (index) => {
if (index > 30) return 'purple';
if (index > 20) return 'blue';
if (index > 10) return 'green';
return 'red';
};
const pieData = data.map((value, index) => ({
value,
svg: {
fill: getFill(index),
},
key: `pie-${index}`,
}));
return (
<PieChart innerRadius="90%" style={styles.pieChart} data={pieData}>
<ProgressCircle
style={styles.progressCircle}
progress={0.7}
backgroundColor="red"
progressColor="green">
<ForeignObject x={-100} y={-100}>
<View style={styles.progressCircleContentContainer}>
<Text style={{...styles.text, color: 'green', marginBottom: 5}}>
Active
</Text>
<View
style={{
...styles.progressCircleContentView,
width: 110,
}}>
<Icon name="heartbeat" size={30} color="red" />
<Text style={styles.text}>72 BPM</Text>
</View>
<View style={styles.progressCircleContentView}>
<Icon name="shoe-prints" size={30} color="red" />
<Text style={styles.text}>4,565</Text>
<Icon name="bolt" size={30} color="red" />
<Text style={styles.text}>45 min</Text>
</View>
<View style={styles.progressCircleContentView}>
<Icon name="fire-alt" size={30} color="red" />
<Text style={styles.text}>1,856</Text>
<Icon name="glass-whiskey" size={30} color="red" />
<Text style={styles.text}>Active</Text>
</View>
<View style={{...styles.progressCircleContentView, width: 150}}>
<Icon name="moon" size={30} color="red" />
<Text style={styles.text}>6 hr 10 min</Text>
</View>
</View>
</ForeignObject>
</ProgressCircle>
</PieChart>
);
}
}
const styles = StyleSheet.create({
pieChart: {
height: 300,
},
progressCircle: {
height: 250,
marginTop: 25,
},
progressCircleContentContainer: {
alignItems: 'center',
width: 200,
height: 200,
transform: [],
},
progressCircleContentView: {
flexDirection: 'row',
justifyContent: 'space-between',
width: 200,
marginBottom: 5,
},
text: {
fontSize: 20,
},
});
What this exmample doesn't do:
Add the backdrop shadow on the circle
Add the icons on the outside of the outer circle
The custom shapes were made with react-native-svg, the library that is used by react-native-svg-charts internally. You can read its documentation here: https://github.com/react-native-community/react-native-svg.
How it looks:
Related
Begginer developer react native.
im dealing with design pattern issue ,
i have multiple TouchableOpacity's in the same component (i have to keep it that way).
for each one i have onPress function thats changs there background and reverse .
the problom is that the function dependent on State current statment and when i click on one of them evreyone is changing .
function Grocery({ navigation }) {
const [isPressed, setIsPressed] = useState(0);
const onPress = () => setIsPressed(!isPressed);
return (
<ScrollView>
<Button title="home" onPress={() => {FindMatch(GetIngridients());navigation.navigate("MatchedRecipiesScreen");}}>press</Button>
<View style={styles.container}>
<TouchableOpacity style={styles.button} onPress={() => {AddToPanetry("pasta");onPress();}} >
<View style={isPressed && styles.pressedButtonStyle} />
<Image style={styles.imageright} source={require('../assets/Pastaa.jpg')} />
<Text> pasta</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => {AddToPanetry("eggs");onPress();}} >
<View style={isPressed && styles.pressedButtonStyle} />
<Image style={styles.imageleft} source={require('../assets/eggs.jpg')} />
<Text>eggs</Text>
</TouchableOpacity>
const styles = StyleSheet.create({
container: {
flexDirection: "row",
flexWrap: "wrap",
padding: 50,
flexWrap: 'wrap',
justifyContent: 'space-between',
}
,
imageleft: {
borderRadius:100,
borderWidth:2,
borderColor:'black',
height: 120,
width: 150,
borderRadius: 80,
padding:25
},
button: {
alignItems: "center",
},
tinyLogo: {
width: 50,
height: 50,
},
pressedButtonStyle: {
position:"absolute",
width:150,
height:121,
backgroundColor:'black',
opacity:0.6,
zIndex:100,
borderRadius:80
},
imageright: {
borderRadius:100,
borderWidth:2,
borderColor:'black',
height: 120,
width: 150,
borderRadius: 80,
padding:25
}
});
Setup an state array
const [isPressed, setIsPressed ] = useState([true, false, false, false, false]);
Here is an sample
You can try something like this, too:
const [isPressed, setIsPressed ] = React.useState('first');
...
<TouchableOpacity style={styles.button} onPress={() => setIsPressed('first')>
<View style={isPressed === 'first' ? styles.pressedButtonStyle : null} />
</TouchableOpacity>
...
<TouchableOpacity style={styles.button} onPress={() => setIsPressed('second')>
<View style={isPressed === 'second' ? styles.pressedButtonStyle : null} />
</TouchableOpacity>
I'm new to React Native and as well to Animations in React Native. What I'm trying to do is to fill the checkbox in it's pressed but the way I did made all the checkboxes fill when I press the Touchable Opacity.
the 'color' value is defined by this
const color = useRef(new Animated.Value(0)).current;
I don't know if this is the best way. I searched through the documentation and saw something like this.
const {
clean,
tasks,
getTasksList,
edited,
toogleEdited,
deleteList,
} = useContext(listContext);
const { taskEdited } = useContext(taskContext);
const [listName, setListName] = useState("");
const screenHeight = Math.round(Dimensions.get("window").height);
const colors = useRef(
Array.from({ length: tasks.length }).fill(new Animated.Value(0))
);
async function getListName() {
setListName(await AsyncStorage.getItem("listName"));
}
async function asyncGetTasks() {
await getTasksList();
}
useEffect(() => {
getListName();
asyncGetTasks();
}, [edited, taskEdited]);
return (
<View style={styles.container}>
<StatusBar hidden />
<View style={styles.buttonsContainer}>
<TouchableOpacity
onPress={() => {
clean();
navigation.goBack();
}}
>
<MaterialIcons name="arrow-back" size={32} />
</TouchableOpacity>
<TouchableOpacity
onPress={() => {
deleteList();
clean();
navigation.goBack();
}}
>
<MaterialIcons name="delete" size={32} color="#bc0000" />
</TouchableOpacity>
</View>
<View style={styles.titleContent}>
<Text style={styles.titleText}>{listName}</Text>
</View>
<ScrollView style={{ height: screenHeight }}>
{tasks.length > 0 ? (
tasks.map((item, index) => (
<TouchableOpacity key={index} style={styles.task}>
<View style={{ flexDirection: "row" }}>
<TouchableOpacity
style={{ alignSelf: "center", marginRight: 8 }}
onPress={() => {
console.log(colors.current[index]);
Animated.timing(colors.current[index], {
toValue: 1,
duration: 1000,
}).start();
toogleEdited();
}}
>
<Animated.View
style={{
borderColor: "#000",
borderWidth: 3,
borderRadius: 100,
}}
>
<Animated.View
style={{
backgroundColor: "#000",
height: 22,
width: 22,
borderRadius: 100,
opacity: colors.current[index],
}}
nativeID={item._id}
></Animated.View>
</Animated.View>
</TouchableOpacity>
<View>
<Text style={styles.taskText}>{item.title}</Text>
</View>
</View>
<Animated.View
style={{
position: "absolute",
alignItems: "center",
alignContent: "center",
opacity: 0.5,
alignSelf: "center",
}}
>
<Text
style={{
color: "#000",
opacity: 0,
fontSize: 32,
}}
>
Done!!
</Text>
</Animated.View>
</TouchableOpacity>
))
) : (
<View style={styles.emptyContent}>
<Text style={styles.emptyText}>This list don't have tasks yet</Text>
</View>
)}
</ScrollView>
<TouchableOpacity
style={{
position: "absolute",
top: screenHeight - 120,
right: 28,
flexDirection: "row",
width: 50,
alignSelf: "flex-end",
}}
onPress={() => navigation.navigate("NewTask")}
>
<Image source={PlusImage} />
</TouchableOpacity>
</View>
);
}
If you don't understand please feel free to ask, my code can be difficult to read but I'm working on that!
edit:
I tried some advises that I got here but still does to all and showed more of the code to be more compreensive
You store all elements as only one ref, you should make it more dynamic like that
const colors = useRef(Array.from({length: tasks.length} , _ => new Animated.Value(0))).current
use .from({ length }, _ => ...) for creating an array with unique object for each slot in the array (and not same object pointed by all slots)
Now you able to change only one element in onPress
onPress={() => {
console.log(colors[index]);
Animated.timing(colors[index], {
toValue: 1,
duration: 1000,
}).start();
}}
Another notes,
Don't use TouchableOpacity where you don't need onPress functionality, it's blocking it children clickability
For achieving animated behavior in Animated.View, you should chain the animation value with view style prop
<Animated.View
style={{ ...yourStyle... ,
opacity: colors[index],
}}
>
will create fading animation, while opacity will be 0 / 1 accords animation value
Please have a look this image
I have an issue in the animation of the circle.
The flow is:
When user will click on button 1, the circle will animate from real position to position 1,
When clicking button2, a circle will move from position 1 to position 2,
and
When clicking on button2, a circle will animate back on the real position.
I need 1 sec. time while animate and I want to set circle position at particular Y position.
mean the first position on Y=400, second position on Y= 100.
Thanks in advance
You need to use the Animated library from react-native. Check out the library for more details on how to animate objects.
Meanwhile check the working example in Snack.io
Here's the code.
import React, { Component } from "react";
import { View, Text, StyleSheet, Animated, TouchableOpacity } from "react-native";
export default class App extends Component {
constructor() {
super();
this.state = {
posY: new Animated.Value(400)
};
}
moveBall = (yPos) => {
Animated.timing(this.state.posY, {
toValue: yPos,
duration: 1000
}).start()
};
renderRectangle = () => {
const animatedStyle = { top: this.state.posY };
return (
<Animated.View style={[styles.rectangle, animatedStyle]}>
</Animated.View>
);
};
render() {
return (
<View style={styles.container}>
<View style={{ flex: 0.9, alignItems: 'center' }}>
{this.renderRectangle()}
</View>
<View style={styles.buttonsContainer}>
<TouchableOpacity
style={styles.buttonStyle}
onPress={() => this.moveBall(250)}
>
<Text>Button 1</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.buttonStyle}
onPress={() => this.moveBall(100)}
>
<Text>Button 2</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.buttonStyle}
onPress={() => this.moveBall(400)}
>
<Text>Button 3</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1
},
rectangle: {
backgroundColor: "#2c3e50",
width: 50,
height: 50,
borderRadius: 50,
position: 'absolute'
},
buttonsContainer: {
flex: 0.1,
flexDirection: 'row',
justifyContent: 'space-between',
paddingLeft: 20,
paddingRight: 20
},
buttonStyle: {
padding: 5,
height: 30,
backgroundColor: 'limegreen'
}
});
I want to dynamically set the value to variables in .map function but it appears to syntax errors. Please help me out.
I used to use {} to wrap the JavaScript code in html but this time it didn't work as expected.
Additionally I also wondering that is it possible to access variables stored in the local state object within .map function.
import React from 'react';
import { View, Text } from 'react-native';
import { Icon, Avatar } from 'react-native-elements';
class SearchListItem extends React.Component {
render() {
const { id, title, shortDescription, time, locationDescription, peopleGroup } = this.props.item;
const indexX = -28;
const indexZ = 1.1;
return (
<View style={styles.containerStyle}>
<View style={{ flexDirection: 'row' }}>
<View style={{ width: '90%' }}>
<Text style={styles.title}>{title}</Text>
</View>
<View style={{ width: '10%' }}>
<Icon
name='star-outline'
type='material-community'
color='#666666' />
</View>
</View>
<View>
<Text style={{ marginTop: 5, color: '#666666' }}>{shortDescription}</Text>
<Text style={{ marginTop: 5 }}>{time}</Text>
<Text style={{ marginTop: 5 }}>{locationDescription}</Text>
</View>
<View style={{ flexDirection: 'row', marginTop: 20 }}>
{const i = 0}
peopleGroup.map((people) => (
<Avatar
width={30}
position='absolute'
containerStyle={{ transform: [{translate: [-28 + (28 * i), 0, 20]}] }}
small
rounded
source={{uri: "http://www.5seestar.com/jiaoxuewen/images/1701/dengchao.jpg"}}
activeOpacity={0.7}
/> ));
</View>
</View>
);
}
};
const styles = {
containerStyle: {
padding: 30,
flexDirection: 'column',
alignItems: 'flex-start',
justifyContent: 'center',
marginTop: 5
},
title: {
fontWeight: 'bold',
fontSize: 18
}
};
export default SearchListItem;
All you want to do is to use the index of the mapped value, so you can use this i guess :
<View style={{ flexDirection: 'row', marginTop: 20 }}>
{
peopleGroup.map((people,i) => (
<Avatar
width={30}
position='absolute'
containerStyle={{ transform: [{translate: [-28 + (28 * i), 0, 20]}] }}
small
rounded
source={{uri:"http://www.5seestar.com/jiaoxuewen/images/1701/dengchao.jpg"}}
activeOpacity={0.7}
/>
));
}
</View>
I am trying to have my Animated View come downward and over the content of the ScrollView instead of over my top fixed position bar, but when the Animation begins the animated view ends up eating the space of the container bar. I have played with paddingTop, marginTop, but seems to be a hack.
Here is a self contained code sample that shows what I'm trying to do:
import React, { Component } from 'react';
import {
AppRegistry, StyleSheet, Text, View, Animated, Dimensions, ScrollView,
Button
} from 'react-native';
const { width } = Dimensions.get('window');
const make_text = (text='Hello', color='blue') => (
<Text
style={{textAlign: 'center', fontSize: 24, backgroundColor: color, margin: 20}}>
{text}
</Text>
);
class Fix_bar extends Component {
state = { height: new Animated.Value(0) };
expand_dropdown = () => {
Animated.timing(this.state.height, {
toValue: 100
}).start();
}
fold_dropdown = () => {
Animated.timing(this.state.height, {
toValue: 0
}).start();
}
render () {
const s = {
position: 'absolute', height: 150, backgroundColor: 'red', paddingTop: 20, width
};
return (
<View style={s}>
<View style={{flexDirection: 'row', flex: 1, justifyContent: 'space-between'}}>
<Text style={{fontSize: 24, paddingTop: 50}}> Left side thing</Text>
<Text style={{fontSize: 24, paddingTop: 50}}> Right side thing</Text>
</View>
<Button title={'Expand'} onPress={this.expand_dropdown}/>
<Button title={'Fold'} onPress={this.fold_dropdown}/>
<View style={{backgroundColor: 'black', height: 1}}/>
<Animated.View style={{height: this.state.height}}>
{make_text('world', 'aliceblue')}
{make_text('world', 'aliceblue')}
{make_text('world', 'aliceblue')}
</Animated.View>
</View>
);
}
}
class animate_example extends Component {
render() {
return (
<View style={{backgroundColor: 'orange', flex: 1}}>
<Fix_bar/>
<ScrollView style={{marginTop: 150}}>
<View style={{justifyContent: 'space-between'}}>
{make_text()}
{make_text()}
{make_text()}
{make_text()}
{make_text()}
</View>
</ScrollView>
</View>
);
}
}
AppRegistry.registerComponent('animate_example', () => animate_example);
One idea I had was to make a trailing View in that fix_bar component with transparency with the height that I intend for the dropdown but haven't explored that idea.
I would suggest the following hierarchy:
const ScrollViewContainer = () =>
<ScrollView style={{marginTop: 150}}>
<View style={{justifyContent: 'space-between'}}>
{make_text()}
{make_text()}
{make_text()}
{make_text()}
{make_text()}
</View>
</ScrollView>;
const ExpandableBar = (props: {expanded: boolean}) =>
<View style={{position: "absolute", top: 0, left: 0, right: 0, bottom: 0}} />
const render = () =>
<View>
<Fix_bar />
<View style={{flex: 1}}> // container which fills remaining space
<ScrollViewContainer />
<ExpandableBar />
</View>
Then in ExpandableBar you'd animate down if expanded is true. also please note that ExpandableBar should be a class (obviously).