I want to save the drawings and notes I make with sketch-canvas in a device folder, but I can not find the form, I do not know how to do it.
I have studied and searched for forms, but I do not know how to apply it to this project.
I do not know if I have to create a module like the facebook documentation says
import React, { Component } from 'react'
import {
Platform,
StyleSheet,
Text,
View,
Alert,
} from 'react-native'
import RNSketchCanvas from '#terrylinla/react-native-sketch-canvas'
export default class App extends Component {
render() {
return (
<View style={styles.container}>
<View style={{ flex: 1, flexDirection: 'row' }}>
<RNSketchCanvas
containerStyle={{ backgroundColor: 'transparent', flex: 1 }}
canvasStyle={{ backgroundColor: 'transparent', flex: 1 }}
defaultStrokeIndex={0}
defaultStrokeWidth={5}
closeComponent={<View style={styles.functionButton}><Text style={{color: 'white'}}>Cerrar</Text></View>}
undoComponent={<View style={styles.functionButton}><Text style={{color: 'white'}}>Deshacer</Text></View>}
clearComponent={<View style={styles.functionButton}><Text style={{color: 'white'}}>Limpiar</Text></View>}
eraseComponent={<View style={styles.functionButton}><Text style={{color: 'white'}}>Borrador</Text></View>}
strokeComponent={color => (
<View style={[{ backgroundColor: color }, styles.strokeColorButton]} />
)}
strokeSelectedComponent={(color, index, changed) => {
return (
<View style={[{ backgroundColor: color, borderWidth: 2 }, styles.strokeColorButton]} />
)
}}
strokeWidthComponent={(w) => {
return (<View style={styles.strokeWidthButton}>
<View style={{
backgroundColor: 'white', marginHorizontal: 2.5,
width: Math.sqrt(w / 3) * 10, height: Math.sqrt(w / 3) * 10, borderRadius: Math.sqrt(w / 3) * 10 / 2
}} />
</View>
)}}
saveComponent={<View style={styles.functionButton}><Text style={{color: 'white'}}>Save</Text></View>}
savePreference={() => {
return {
folder: 'RNSketchCanvas',
filename: String(Math.ceil(Math.random() * 100000000)),
transparent: false,
imageType: 'png'
}
}}
//onSketchSaved={(success, filePath) => { alert('filePath: ' + filePath); }}
/>
</View>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
},
headerText: {
fontSize: 5,
textAlign: "center",
margin: 10,
fontWeight: "bold"
},
strokeColorButton: {
marginHorizontal: 2.5, marginVertical: 8, width: 30, height: 30, borderRadius: 15,
},
strokeWidthButton: {
marginHorizontal: 2.5, marginVertical: 8, width: 30, height: 30, borderRadius: 15,
justifyContent: 'center', alignItems: 'center', backgroundColor: '#39579A'
},
functionButton: {
marginHorizontal: 2.5, marginVertical: 8, height: 30, width: 60,
backgroundColor: '#39579A', justifyContent: 'center', alignItems: 'center', borderRadius: 5,
}
})
You should not create a database.
In this simple application there is a line that would be used to save, but I do not know how to use it.
I show you the code that I have.
Can you tell me how or where should I start?
EDIT:
I think this is the line that I should use to save the created bubbles:
// onSketchSaved = {(success, filePath) => {alert ('filePath:' + filePath); }}
But I do not know how to do it, I do not know what to add to save my drawings on Android
Thank you
From the RNSketchCanvas documentation:
onSketchSaved (function):
An optional function which accpets 2 arguments success and path. If success is true, image is saved successfully and the saved image path might be in second argument. In Android, image path will always be returned. In iOS, image is saved to camera roll or file system, path will be set to null or image location respectively.
Essentially, you are looking for the filepath where your image is stored.
If the image was stored in the camera roll (path is null) you can use the CameraRoll api to retrieve the image path.
Otherwise, you already have a file path for the image. If you then want to move the image you can make use of the moveFile function within React Native File System library (or FileSystem API if you are using Expo) to move the file to a folder of your choosing.
This is untested code but should provide a more tangible example of how this process may look:
import React, {Component} from 'react'
import {StyleSheet, Text, View, CameraRoll} from 'react-native'
import RNSketchCanvas from '#terrylinla/react-native-sketch-canvas'
import RNFS from 'react-native-fs';
export default class App extends Component {
render() {
return (
<View style={styles.container}>
<View style={{ flex: 1, flexDirection: 'row' }}>
<RNSketchCanvas
containerStyle={{ backgroundColor: 'transparent', flex: 1 }}
canvasStyle={{ backgroundColor: 'transparent', flex: 1 }}
defaultStrokeIndex={0}
defaultStrokeWidth={5}
closeComponent={<View style={styles.functionButton}><Text style={{color: 'white'}}>Cerrar</Text></View>}
undoComponent={<View style={styles.functionButton}><Text style={{color: 'white'}}>Deshacer</Text></View>}
clearComponent={<View style={styles.functionButton}><Text style={{color: 'white'}}>Limpiar</Text></View>}
eraseComponent={<View style={styles.functionButton}><Text style={{color: 'white'}}>Borrador</Text></View>}
strokeComponent={color => (
<View style={[{ backgroundColor: color }, styles.strokeColorButton]} />
)}
strokeSelectedComponent={(color, index, changed) => {
return (
<View style={[{ backgroundColor: color, borderWidth: 2 }, styles.strokeColorButton]} />
)
}}
strokeWidthComponent={(w) => {
return (<View style={styles.strokeWidthButton}>
<View style={{
backgroundColor: 'white', marginHorizontal: 2.5,
width: Math.sqrt(w / 3) * 10, height: Math.sqrt(w / 3) * 10, borderRadius: Math.sqrt(w / 3) * 10 / 2
}} />
</View>
)}}
saveComponent={<View style={styles.functionButton}><Text style={{color: 'white'}}>Save</Text></View>}
savePreference={() => {
return {
folder: 'RNSketchCanvas',
filename: String(Math.ceil(Math.random() * 100000000)),
transparent: false,
imageType: 'png'
}
}}
onSketchSaved={this.onSave}
/>
</View>
</View>
)
}
onSave = async (success, path) => {
if(!success) return;
let imageUri;
const myNewImagePath = RNFS.DocumentDirectoryPath + 'my_folder'
try{
if(path == null){
// image has been saved to the camera roll
// Here I am assuming that the most recent photo in the camera roll is the saved image, you may want to check the filename
const images = await CameraRoll.getPhotos({first: 1});
if(images.length > 0){
imageUri = [0].image.uri;
}else{
console.log('Image path missing and no images in camera roll')
return;
}
} else{
imageUri = path
}
await RNFS.moveFile(imageUri, myNewImagePath)
} catch (e) {
console.log(e.message)
}
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
},
headerText: {
fontSize: 5,
textAlign: "center",
margin: 10,
fontWeight: "bold"
},
strokeColorButton: {
marginHorizontal: 2.5, marginVertical: 8, width: 30, height: 30, borderRadius: 15,
},
strokeWidthButton: {
marginHorizontal: 2.5, marginVertical: 8, width: 30, height: 30, borderRadius: 15,
justifyContent: 'center', alignItems: 'center', backgroundColor: '#39579A'
},
functionButton: {
marginHorizontal: 2.5, marginVertical: 8, height: 30, width: 60,
backgroundColor: '#39579A', justifyContent: 'center', alignItems: 'center', borderRadius: 5,
}
})
Related
How can I add a border radius to my image from each side without affecting the username text? I want to make the image feel good by adding a border radius from each side like yt shorts so what I did I gave it borderTopLeftRadius borderTopRightRadius 30 each same with the bottom but then it makes the username text looks bad can you help me with that? I am using react native
import React from 'react';
import { StyleSheet, Text, View, Image, ActivityIndicator } from 'react-native';
import { useState } from 'react';
const PostCard = ({ username, profile_image, postImage }) => {
const [isLoading, setIsLoading] = useState(true);
return (
<View style={styles.container}>
<View style={styles.c1}>
<Image
source={{ uri: profile_image }}
style={styles.profilepic}
onLoadEnd={() => setIsLoading(false)}
/>
{isLoading && <ActivityIndicator style={styles.spinner} />}
<Text style={styles.username}>{username}</Text>
</View>
<Image
source={{ uri: postImage }}
style={styles.image} // this is the image that i want to style
onLoadEnd={() => setIsLoading(false)}
/>
{isLoading && <ActivityIndicator style={styles.spinner} />}
</View>
);
};
export default PostCard
const styles = StyleSheet.create({
container: {
backgroundColor: 'white',
width: '100%',
// height: 350,
borderRadius: 10,
marginVertical: 10,
overflow: 'hidden',
borderColor: 'white',
borderWidth: 1,
},
c1: {
width: '100%',
flexDirection: 'row',
alignItems: 'center',
padding: 10,
backgroundColor: 'black',
},
profilepic: {
width: 30,
height: 30,
borderRadius: 30,
borderColor: 'white',
borderWidth: 1,
},
username: {
color: 'white',
marginLeft: 10,
fontSize: 17,
fontWeight: 'bold',
},
image: {
width: '130%',
aspectRatio: 1,
}
})
I have implemented tensor-flow camera functionalities for pose detection on a website and then hosted it on netlify. Link: https://uactivsite-mobile.netlify.app/.Also github link of the same: https://github.com/viveksgonal/uactivsite/blob/main/src/App.js
I am using this as webview on react-native app. The first time the app builds perfectly and the camera starts. But whenever I try to reload it or run npx react-native start the second time, the camera never opens.
If anyone knows where I'm going wrong, it would be pleasure if you provide the solution. Thank you.
Code is attached below for the react-native app part:
/* eslint-disable react-native/no-inline-styles */
import React, { useRef, useState } from 'react';
const exercises = [
{
name: 'High Knees',
total: 20,
index: 0
},
{
name: 'Jumping Jacks',
total: 25,
index: 1
},
{
name: 'Squats',
total: 20,
index: 2
},
]
import WebView from 'react-native-webview'
import {
View,
StyleSheet,
Text,
Image,
TouchableWithoutFeedback,
Modal
} from 'react-native';
import { useNavigation } from '#react-navigation/native';
const ExerciseCamera = () => {
const webviewRef = useRef(null)
const navigation = useNavigation();
const [speed, setSpeed] = useState(0)
const [reps, setReps] = useState(0)
const ex = 1
function getInjectableJSMessage(message) {
return `
(function() {
window.dispatchEvent(new MessageEvent('message', {
data: ${JSON.stringify(message)}
}));
})();
`;
}
function onMessage(data) {
let val = JSON.parse(data.nativeEvent.data)
if (val.type === 'reps') {
setReps(val.data.rep)
if (val.data.speed !== 0) {
setSpeed(val.data.speed)
}
}
else if (val.type === 'completed') {
navigation.navigate('dashboard', {
screen: 'completeddailyexercise',
});
}
else {
console.log(val.data.rep)
}
}
function sendDataToWebView(msg) {
webviewRef.current.injectJavaScript(
getInjectableJSMessage(msg)
);
}
return (
<View style={styles.container}>
<Modal
transparent={true}
visible={true}
>
<View style={styles.top_container}>
<TouchableWithoutFeedback
onPress={() => {
navigation.navigate('dashboard', {
screen: 'completeddailyexercise',
});
}}>
<Image
style={styles.icons_container}
source={require('../../Assets/play.png')}
/>
</TouchableWithoutFeedback>
<View style={styles.exercise_name_container}>
<Text style={styles.exercise_name}>Side lunges</Text>
</View>
<TouchableWithoutFeedback
onPress={() => {
navigation.navigate('dashboard', { screen: 'dailychallange' });
}}>
<View style={styles.icons_container}>
<Image
style={styles.icon}
source={require('../../Assets/close.png')}
/>
</View>
</TouchableWithoutFeedback>
</View>
<View style={styles.bottom_container}>
<View style={styles.timer_container}>
<Text style={styles.timer_text}>02:47</Text>
</View>
{reps > 0 ? (
<View
style={[
styles.number_container,
{ justifyContent: speed > 0 ? 'space-between' : 'center' },
]}>
{speed > 0 ? <Text style={styles.number}>{speed} RS</Text> : null}
<Text style={styles.number}>{reps}/{exercises[ex].total}</Text>
</View>
) : null}
</View>
</Modal>
<WebView
ref={webviewRef}
mediaPlaybackRequiresUserAction={false}
source={{ uri: 'https://uactivsite-mobile.netlify.app/' }}
scalesPageToFit={false}
mixedContentMode="compatibility"
onMessage={onMessage}
onLoad={event => {
sendDataToWebView({
data: exercises[ex],
type: 'exercise'
})
}}
/>
</View>
);
};
const styles = StyleSheet.create({
container: { flex: 1 },
preview: {
flex: 1,
},
top_container: {
zIndex: 1,
position: 'absolute',
top: 43,
paddingHorizontal: 20,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
width: '100%',
},
bottom_container: {
zIndex: 1,
position: 'absolute',
bottom: 0,
width: '100%',
},
number: { color: 'white', fontSize: 28 },
exercise_name_container: {
height: 40,
width: 155,
alignItems: 'center',
justifyContent: 'center',
borderRadius: 20,
backgroundColor: 'rgba(255,255,255,0.2)',
},
number_container: {
height: 62,
backgroundColor: 'black',
width: '100%',
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 19,
},
timer_container: {
width: '100%',
height: 78,
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
backgroundColor: 'rgba(255,255,255,0.45)',
alignItems: 'center',
},
timer_text: { color: 'black', fontSize: 48, fontFamily: 'Poppins-Bold' },
icons_container: {
height: 40,
width: 40,
alignItems: 'center',
justifyContent: 'center',
borderRadius: 50,
backgroundColor: 'rgba(255,255,255,0.8)',
},
icon: { width: 16, height: 16, resizeMode: 'contain' },
exercise_name: { color: 'black', fontFamily: 'Poppins-SemiBold', fontSize: 23 },
});
export default ExerciseCamera;
UPDATED CODE
This now fetches the data when button clicked but I cant display it as it did when it loaded first time?
I am totally new with react native so I am sorry if I explain my problem wrong or seem a little thick. I have made a screen that fetches data and displays the data and it seems to work quite well. However I have a couple of buttons and I want to add an onclick to call a function.
Maybe I am getting this wrong but its supposed to work like javascript which I have no problem with but I think I am missing something with the difference between components and functions.
For example in my code its just automatically fetches the data and displays it. How would I make functions to load the data when one the buttons is clicked and also update the view with the new loaded data?
I have tried putting the functions in with the fetch data but I seem to have to add everything but surely I can make re-usable functions for each task like I would in javascript.
I have included my code for the page and also what I have tried. Any help of advice would be great as when I am researching on the net I get confused information between reactjs and native.
Also all the code below has been snippets taken from various places and played around with so it is totally probably all wrong in terms of structure.
The code :
import React from "react";
import {
StyleSheet,
View,
ActivityIndicator,
FlatList,
Text,
StatusBar,
Image,
TouchableOpacity,
ScrollView,
SafeAreaView
} from "react-native";
import Icon from "react-native-vector-icons/Entypo";
import CupertinoButtonPurple1 from "../components/CupertinoButtonPurple1";
import Removebutton from "../components/removebutton";
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: true,
dataSource:[] };
}
componentDidMount(){
fetch("https://www.uberfantasies.com/testv2.php")
.then(response => response.json())
.then((responseData)=> {
this.setState({
loading: false,
dataSource: responseData.data
})
})
.catch(error=>console.log(error)) //to catch the errors if any
}
FlatListItemSeparator = () => {
return (
<View/>
);
}
renderItem=(data)=>
<SafeAreaView>
<View style={styles.container}>
<View style={styles.rect}>
<View style={styles.imageRow}>
<Image source={{uri: data.item.image}} style={styles.image} />
<View style={styles.group2Column}>
<View style={styles.group2}>
<Text style={styles.bitch}>
<Text>{data.item.from} sent you a mesage!</Text>
</Text>
<Text style={styles.loremIpsum}>
"{data.item.message}"
</Text>
</View>
<View style={styles.loremIpsum2Row}>
<Text style={styles.loremIpsum2}>{data.item.when}</Text>
<View style={styles.loremIpsum2Filler}></View>
<View style={styles.group3}>
<CupertinoButtonPurple1
style={styles.cupertinoButtonPurple1}
></CupertinoButtonPurple1>
<Removebutton
style={styles.removebutton}
></Removebutton>
</View>
</View>
</View>
</View>
</View>
</View>
</SafeAreaView>
render(){
if(this.state.loading){
return(
<View style={styles.loader}>
<ActivityIndicator size="large" color="#0c9"/>
</View>
)}
return(
<View style={styles.container}>
<FlatList
data= {this.state.dataSource}
ItemSeparatorComponent = {this.FlatListItemSeparator}
renderItem= {item=> this.renderItem(item)}
keyExtractor= {item=>item.id.toString()}
/>
</View>
)}
}
const styles = StyleSheet.create({
container: {
flex: 1
},
loader:{
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#fff"
},
rect: {
height: 97,
backgroundColor: "rgba(230,230, 230,0.57)",
borderWidth: 0,
borderColor: "rgba(0,0,0,0.57)",
marginTop: 0,
borderBottomWidth: 1,
borderBottomColor: "#d5d5d5",
backgroundColor: "#f4f4f4"
},
image: {
width: 80,
height: 80,
borderRadius: 15,
borderWidth: 4,
borderColor: '#ffffff',
shadowColor: '#d5d5d5',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.8,
shadowRadius: 2
},
group2: {
height: 41
},
bitch: {
fontFamily: "sans-serif-condensed",
color: "#121212",
fontSize: 14,
height: 17,
fontWeight: "bold",
marginTop: 2
},
loremIpsum: {
fontFamily: "sans-serif-condensed",
color: "#121212",
height: 17,
width: 159,
marginTop: 4
},
loremIpsum2: {
fontFamily: "sans-serif-condensed",
color: "#121212",
fontSize: 10,
marginTop: 8
},
loremIpsum2Filler: {
flex: 1,
flexDirection: "row"
},
group3: {
width: 125,
height: 26,
flexDirection: "row",
justifyContent: "space-between",
marginRight: 25
},
cupertinoButtonPurple1: {
height: 25,
width: 57
},
cupertinoButtonDanger2: {
height: 25,
width: 57
},
loremIpsum2Row: {
height: 26,
flexDirection: "row",
marginTop: 17,
marginRight: 33,
width: "100%"
},
group2Column: {
width: 275,
marginLeft: 16
},
imageRow: {
height: 84,
flexDirection: "row",
marginTop: 8,
marginLeft: 4
}
});
and the way I have tried to make a function and the way I think it should work with results?
The UPDATED code that fetches data but I cant get it to display data how it did in the previous code? Going out my nut here because I think Im missing something silly. If I had only one element to display or change I could do it but I think its because it looks through the results? Am i wrong?
Heres the code:
import React, { useState, Component } from 'react'
import {
StyleSheet,
View,
ActivityIndicator,
FlatList,
Text,
StatusBar,
Image,
TouchableOpacity,
ScrollView,
SafeAreaView
} from 'react-native'
class App extends Component {
state = {
loading: true,
dataSource:[],
Status: "Not loaded"
}
onPress = () => {
fetch("https://www.uberfantasies.com/testv.php")
.then(response => response.json())
.then((responseData)=> {
this.setState({
loading: false,
Status: "Loaded",
dataSource: responseData.data
})
console.log(this.state.dataSource)
})
.catch(error=>console.log(error)) //to catch the errors if any
}
render() {
return (
<View style={styles.container}>
<TouchableOpacity
style={styles.button}
onPress={this.onPress}
>
<Text>Click me</Text>
</TouchableOpacity>
<View>
<Text>
Status : { this.state.Status }
</Text>
</View>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
button: {
alignItems: 'center',
backgroundColor: '#DDDDDD',
padding: 10,
marginBottom: 10
},
loader:{
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#fff"
}
})
export default App;
if you want to call a function within onPress you need to call it. Like
<Button title="Press Me" onPress={() => ReloadData()} />
Below is a sample code snippet. I have used the function component as it is easy for a beginner. Assuming your output of the API call is a list, I am setting it to the state variable. SO whenever the 'apiData' variable value changes your component will re-render. You can user either a button or a touchable wrapper component for a clickable item.
const [apiData, setApiData] = useState([]);
const MySampleComponent = () => {
const apiCall = () => {
//Your code
setApiData(result);
};
const renderListItem = (itemData) => <Text>{itemData.item.<your key>}</Text>;
return (
<View>
<FlatList
keyExtractor={item => item.id}
data={apiData}
renderItem={renderListItem}
/>
<Button onPress={apiCall} />
<TouchableOpacity onPress={apiCall}>
<Text>Click Me</Text>
</TouchableOpacity>
</View>
);
};
Thanks for your comments and help, I think I have a much better way of understanding a few things now. I have managed to get a load button to fetch data and display it in the way as previously managed. I know it does not look like much progress but trust me this is a big step to getting to grips with the way things work for me.
Now time to play around with it, thanks again.
The working code (well best I can do at the minute!)
import React, { useState, Component } from 'react';
import {
StyleSheet,
View,
ActivityIndicator,
FlatList,
Text,
StatusBar,
Image,
TouchableOpacity,
ScrollView,
SafeAreaView,
} from 'react-native';
import Icon from 'react-native-vector-icons/Entypo';
import CupertinoButtonPurple1 from '../components/CupertinoButtonPurple1';
import CupertinoButtonDanger2 from '../components/CupertinoButtonDanger2';
class App extends Component {
state = {
loading: false,
dataSource: [],
Status: 'Not loaded',
};
componentDidMount() {
// this.onPress();
}
onPress = () => {
this.setState({
loading: true,
});
fetch('https://www.uberfantasies.com/testv.php')
.then((response) => response.json())
.then((responseData) => {
this.setState({
loading: false,
Status: 'Loaded',
dataSource: responseData.data,
});
console.log(this.state.dataSource);
})
.catch((error) => console.log(error)); //to catch the errors if any
};
FlatListItemSeparator = () => {
return <View />;
};
renderItem = (data) => (
<SafeAreaView>
<View style={styles.container}>
<View style={styles.rect}>
<View style={styles.imageRow}>
<Image source={{ uri: data.item.image }} style={styles.image} />
<View style={styles.group2Column}>
<View style={styles.group2}>
<Text style={styles.bitch}>
Bitch from Cov sent you a mesage!
</Text>
<Text style={styles.loremIpsum}>
"Hi there you Sexy Beast!"
</Text>
</View>
<View style={styles.loremIpsum2Row}>
<Text style={styles.loremIpsum2}>12 Feb 2022, 6.05 pm</Text>
<View style={styles.loremIpsum2Filler}></View>
<View style={styles.group3}>
<CupertinoButtonPurple1
style={
styles.cupertinoButtonPurple1
}></CupertinoButtonPurple1>
<CupertinoButtonDanger2
style={
styles.cupertinoButtonDanger2
}></CupertinoButtonDanger2>
</View>
</View>
</View>
</View>
</View>
</View>
</SafeAreaView>
);
render() {
if (this.state.loading) {
return (
<View style={styles.loader}>
<ActivityIndicator size="large" color="#0c9" />
</View>
);
}
return (
<View style={styles.container}>
<TouchableOpacity style={styles.button} onPress={this.onPress}>
<Text>Click me</Text>
</TouchableOpacity>
<View>
<Text>Status : {this.state.Status}</Text>
</View>
<FlatList
data={this.state.dataSource}
ItemSeparatorComponent={this.FlatListItemSeparator}
renderItem={(item) => this.renderItem(item)}
keyExtractor={(item) => item.id.toString()}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
button: {
alignItems: 'center',
backgroundColor: '#DDDDDD',
padding: 10,
marginBottom: 10,
},
loader: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#fff',
},
rect: {
height: 97,
backgroundColor: 'rgba(230,230, 230,0.57)',
borderWidth: 0,
borderColor: 'rgba(0,0,0,0.57)',
marginTop: 0,
borderBottomWidth: 1,
borderBottomColor: '#d5d5d5',
backgroundColor: '#f4f4f4',
},
image: {
width: 80,
height: 80,
borderRadius: 15,
borderWidth: 4,
borderColor: '#ffffff',
boxShadow: '0px 2px 4px 0px rgb(0 0 0 / 55%)',
},
group2: {
width: 275,
height: 41,
},
bitch: {
fontFamily: '-apple-system,Segoe UI,Roboto,sans-serif',
color: '#121212',
fontSize: 14,
height: 17,
fontWeight: 'bold',
marginTop: 2,
},
loremIpsum: {
fontFamily: '-apple-system,Segoe UI,Roboto,sans-serif',
color: '#121212',
height: 17,
width: 159,
marginTop: 4,
},
loremIpsum2: {
fontFamily: '-apple-system,Segoe UI,Roboto,sans-serif',
color: '#121212',
fontSize: 10,
marginTop: 8,
},
loremIpsum2Filler: {
flex: 1,
flexDirection: 'row',
},
group3: {
width: 121,
height: 26,
flexDirection: 'row',
justifyContent: 'space-between',
},
cupertinoButtonPurple1: {
height: 25,
width: 57,
},
cupertinoButtonDanger2: {
height: 25,
width: 57,
},
loremIpsum2Row: {
height: 26,
flexDirection: 'row',
marginTop: 17,
marginRight: 3,
},
group2Column: {
width: 275,
marginLeft: 16,
},
imageRow: {
height: 84,
flexDirection: 'row',
marginTop: 8,
marginLeft: 4,
},
});
export default App;
Here is my model.
I would like this animation :
When I swipe left, the month March takes the central place, and April replaces March in the right
When I swipe right, the month January takes central place, and December replaces January in the left
I literally don't know where to begin, or how to achieve this.
For the code used in the image, here it is :
import React from 'react';
import {View, StyleSheet, Text, TouchableOpacity} from 'react-native';
const MonthSlider = () => {
return (
<View
style={{
flexDirection: 'row',
flex: 0.2,
paddingBottom: 100,
}}>
<View
style={{
flexDirection: 'column',
flex: 0.25,
alignItems: 'center',
marginTop: 10,
}}>
<TouchableOpacity
style={{alignItems: 'center'}}
onPress={() => alert('January clicked')}>
<View style={styles.nonActiveCircle} />
<Text style={styles.nonActiveMonth}>January</Text>
</TouchableOpacity>
</View>
<View
style={{
flexDirection: 'column',
flex: 0.5,
alignItems: 'center',
marginTop: 10,
}}>
<View style={styles.activeCircle} />
<Text style={styles.year}>2021</Text>
<Text style={styles.activeMonth}>February</Text>
</View>
<View
style={{
flexDirection: 'column',
flex: 0.25,
marginTop: 10,
alignItems: 'center',
}}>
<TouchableOpacity
style={{alignItems: 'center'}}
onPress={() => alert('March clicked')}>
<View style={styles.nonActiveCircle} />
<Text style={styles.nonActiveMonth}>March</Text>
</TouchableOpacity>
</View>
</View>
);
};
const styles = StyleSheet.create({
nonActiveMonth: {
fontSize: 20,
color: '#8BA8C3',
fontWeight: 'bold',
},
activeMonth: {
fontSize: 30,
color: 'white',
fontWeight: 'bold',
},
nonActiveCircle: {
width: 8,
height: 8,
borderRadius: 8 / 2,
backgroundColor: '#8BA8C3',
marginTop: 10,
},
activeCircle: {
width: 25,
height: 25,
borderRadius: 25 / 2,
backgroundColor: 'white',
borderWidth: 5,
borderColor: '#175287',
bottom: 20,
marginBottom: -20,
},
year: {
fontSize: 20,
color: '#8BA8C3',
},
});
export default MonthSlider;
Maybe a good start would be use 'react-view-slider' or 'ScrollView' and do something like this :
import React, { useState } from 'react';
import {View, StyleSheet, Text, TouchableOpacity} from 'react-native';
import Swiper from 'react-native-swiper';
const MonthSlider = () => {
// Months
const months = ["January","February","March","April","May","June","July","August","September","October","November","December"];
// State iMonths
const [ iMonth, setIMonth ] = useState(1);
// Month click
const MonthClick = (i) => {
alert( months[i] +' clicked')
setIMonth(i);
};
// This function renders the view at the given index.
const renderView = ({ index, active }) => (
months.map( (month,i) =>
<View key={i} style={styles.month + ( active == i ) ? styles.active : styles.inactive }>
<TouchableOpacity
style={styles.bt}
onPress={() => MonthClick(i)}
>
<View style={ active == i ? styles.activeCircle : styles.nonActiveCircle } />
<Text style={ active == i ? styles.activeMonth : styles.nonActiveMonth }>{month}</Text>
</TouchableOpacity>
</View>
)
);
return (
<Swiper style={styles.monthWrapper} showsButtons={false} horizontal={true} showsPagination={false}>
{renderView(0,0)}
</Swiper>
);
};
const styles = StyleSheet.create({
/* New styles */
monthWrapper:{
flex:0.5,
display:'flex',
flexDirection: 'row',
height:'100px',
textAlign:'center',
},
bt:{
textAlign:"center"
},
month:{
alignItems: 'center',
backgroundColor: '#9DD6EB'
},
active:{
color:'#000',
flex: 0.5,
opacity:1,
fontSize: 30,
color: 'white',
fontWeight: 'bold',
},
inactive: {
fontSize: 20,
color: '#8BA8C3',
fontWeight: 'bold',
},
/* Old styles */
nonActiveMonth: {
fontSize: 20,
color: '#8BA8C3',
fontWeight: 'bold',
},
activeMonth: {
fontSize: 30,
color: 'white',
fontWeight: 'bold',
},
nonActiveCircle: {
width: 12,
height: 12,
borderRadius: '100%',
backgroundColor: '#8BA8C3',
marginTop: 10,
alignSelf:'center'
},
activeCircle: {
width: 40,
height: 40,
borderRadius: '100%',
backgroundColor: 'white',
borderWidth: 5,
borderColor: '#175287',
bottom: 20,
marginBottom: -20,
},
});
export default MonthSlider;
I'm having the following problem: "undefined is not an object (evaluating 'u.stopTracking')".
It happens when on Expo I update a props, I tried to use on componentWillReceiveProps, stopAnimation() and stopTracking(), but I could not.
Link expo: Here
To make the error appear, just click on the image of the central player.
Can someone give me a hand?
App:
import * as React from 'react';
import { Text, View, StyleSheet, ImageBackground } from 'react-native';
import { Constants } from 'expo';
import Album from './Album';
import Track from './Track';
const State = ['normal', 'transparent', 'big'];
export default class App extends React.Component {
constructor() {
super();
this.state = {
type: 0,
};
}
render() {
let { type } = this.state;
return (
<View style={styles.container}>
<ImageBackground
source={{
uri:
'https://i.pinimg.com/originals/62/6f/84/626f84c40696c1308a77fd8331e12b3e.jpg',
}}
imageStyle={{ borderRadius: 4 }}
style={{
alignItems: 'center',
justifyContent: 'center',
height: 400,
width: 400,
}}>
<Album
type={State[type]} //normal,transparent,big
title={Track.name}
artist={Track.artists[0].name}
cover={Track.album.images[0].url}
onPress={() => {
type = ++type % 3;
this.setState({ type });
}}
/>
</ImageBackground>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#fff',
},
});
Album:
import * as React from 'react';
import {
Text,
View,
StyleSheet,
ImageBackground,
Animated,
TouchableOpacity,
} from 'react-native';
const size = 40;
export default class Album extends React.Component {
constructor(props) {
super(props);
this.min = size / 4;
this.max = size / 2;
this.heightCenter = new Animated.Value(this.min);
this.heightLateral = new Animated.Value(size / 2);
/*this.state = {
heightCenter: new Animated.Value(this.min),
heightLateral: new Animated.Value(size / 2),
};*/
}
animateBar = (el, value) => {
var newValue = value == this.max ? this.min : this.max;
Animated.timing(el, {
toValue: value,
}).start(() => this.animateBar(el, newValue));
};
onPress = e => {
return this.props.onPress(e);
};
componentDidMount() {
console.log(this.heightCenter)
this.animateBar(this.heightCenter, this.min);
this.animateBar(this.heightLateral, this.max);
}
componentWillReceiveProps(nextProps) {
if (nextProps.type !== this.props.type) {
console.log('componentWillReceiveProps');
//this.state.heightCenter.stopAnimation();
//this.state.heightLateral.stopAnimation();
//Animated.stopTracking();
//Animated.timing(this.heightCenter).stopTracking();
//Animated.timing(this.heightLateral).stopTracking();
/*this.state.heightCenter.stopTracking();
this.state.heightLateral.stopTracking();
this.state.heightCenter.stopAnimation();
this.state.heightLateral.stopAnimation();*/
//this.heightCenter = {};
//this.heightLateral = null;
//this.heightCenter.stopTracking();
//this.heightLateral.stopTracking();
//this.state.heightCenter.stopAnimation();
//this.state.heightLateral.stopAnimation();
console.log(this.heightCenter)
}
}
componentDidUnmount() {
console.log('componentDidUnmount');
//Animated.timing(this.heightCenter).stop();
//Animated.timing(this.heightLateral).stop();
}
componentDidUpdate() {
this.animateBar();
}
render() {
let { type, title, artist, cover } = this.props;
let barWidthCenter = {
height: this.heightCenter,
};
let barWidthLateral = {
height: this.heightLateral,
};
if (type != 'normal' && type != 'transparent' && type != 'big')
type = 'transparent';
let backgroundColor =
type == 'normal' ? 'rgba(255,255,255,1)' : 'rgba(255,255,255,0.5)';
let color = type == 'normal' ? '#000' : '#fff';
if (type == 'big')
return (
<TouchableOpacity onPress={() => this.onPress()}>
<View
style={{
alignItems: 'center',
justifyContent: 'center',
}}>
<ImageBackground
source={{
uri: cover,
}}
imageStyle={{ borderRadius: 4 }}
style={{
flexDirection: 'row',
alignItems: 'flex-end',
justifyContent: 'flex-start',
height: 200,
width: 200,
}}>
<View
style={{
borderRadius: 4,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'rgba(0,0,0,0.3)',
padding: 5,
height: 40,
width: 40,
margin: 5,
}}>
<Animated.View
style={[
{
backgroundColor: 'rgba(255,255,255,1)',
width: 5,
borderRadius: 5 / 2,
margin: 2,
},
barWidthLateral,
]}
/>
<Animated.View
style={[
{
backgroundColor: 'rgba(255,255,255,1)',
width: 5,
borderRadius: 5 / 2,
margin: 2,
},
barWidthCenter,
]}
/>
<Animated.View
style={[
{
backgroundColor: 'rgba(255,255,255,1)',
width: 5,
borderRadius: 5 / 2,
margin: 2,
},
barWidthLateral,
]}
/>
</View>
</ImageBackground>
<View style={{ paddingLeft: 12, paddingRight: 12 }}>
<Text style={{ fontWeight: 'bold', color: '#fff' }}>{title}</Text>
<Text style={{ color: '#fff' }}>{artist}</Text>
</View>
</View>
</TouchableOpacity>
);
return (
<TouchableOpacity onPress={() => this.onPress()}>
<View
style={{
backgroundColor: backgroundColor,
flexDirection: 'row',
justifyContent: 'center',
borderRadius: 4,
padding: 4,
}}>
<ImageBackground
source={{
uri: cover,
}}
imageStyle={{ borderRadius: 4 }}
style={{
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
height: size,
width: size,
}}>
<Animated.View
style={[
{
backgroundColor: 'rgba(255,255,255,1)',
width: 5,
borderRadius: 5 / 2,
margin: 2,
},
barWidthLateral,
]}
/>
<Animated.View
style={[
{
backgroundColor: 'rgba(255,255,255,1)',
width: 5,
borderRadius: 5 / 2,
margin: 2,
},
barWidthCenter,
]}
/>
<Animated.View
style={[
{
backgroundColor: 'rgba(255,255,255,1)',
width: 5,
borderRadius: 5 / 2,
margin: 2,
},
barWidthLateral,
]}
/>
</ImageBackground>
<View style={{ paddingLeft: 12, paddingRight: 12 }}>
<Text style={{ fontWeight: 'bold', color }}>{title}</Text>
<Text style={{ color }}>{artist}</Text>
</View>
</View>
</TouchableOpacity>
);
}
}
I see it's been a while you asked this question. I don't know how you solved this problem but I've had the same error:
"undefined is not an object (evaluating 'u.stopTracking')"
because of the code here:
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
elementPositionX: 0,
target: null,
marginLeft: new Animated.Value(0),
};
It was happening because I had put the Animated Value in the state. It should have defined out of the state, as a property of the component class, like this:
export default class App extends React.Component {
constructor(props) {
super(props);
this.marginLeft= new Animated.Value(0);
this.state = {
elementPositionX: 0,
target: null,
};
The documentation about Animated API is so poor, so I am not sure why but this solved my problem.
EDIT:
I have managed to place it in the state somehow, and it works without giving the former error. However, I need to use this code to change the animated value: this.state.marginLeft2.setValue(amount); and this is actually changing the state directly - without using .setState(). It doesn't seem good to me.