ReactNative Animated width of a view doesn't work - react-native

I want to animate a view's width change in React Native. It's the theWidth value below:
class MyView extends Component {
state = {
theWidth: new Animated.Value(10),
}
compontentDidMount() {
Animated.timing(
this.state.theWidth,
{
toValue: 100,
duration: 10000,
}
).start();
}
render() {
let { theWidth } = this.state;
return (
<Animated.View
style={{
...this.props.style,
width: theWidth,
}}
>
{this.props.children}
</Animated.View>
);
}
}
export default class HomeScreen extends Component {
render() {
return (
<View style={styles.container}>
<MyView style={{ width: 550, height: 50, backgroundColor: 'red' }}>
<Text style={{ fontSize: 28, textAlign: 'center', margin: 10 }}>Fa2ding in1</Text>
</MyView>
</View>
);
}
}
Seems the width value (theWidth) hasn't changed. How to debug this?

Related

React Native Panresponder issue after retouching and moving the image return back to initial position

I have one draggable car image if i dragging the car first time it works fine after second time re dragging the car image return back to the initial position. I want to drag an image smooth and draggable with finger touch. please help me
import React, { Component } from 'react';
import { StyleSheet, View, Text, PanResponder, Animated, Easing, Dimensions, Image, Button } from 'react-native';
import { ToastAndroid } from 'react-native';
export default class Viewport extends Component {
constructor(props) {
super(props);
this.state = {
disableCar: false,
dropZoneCar: null,
panCar: new Animated.ValueXY(),
};
this.carFunction();
}
carFunction = () => {
this.panResponderCar = PanResponder.create({
onStartShouldSetPanResponder: () => true,
onPanResponderMove: Animated.event([null, {
dx: this.state.panCar.x,
dy: this.state.panCar.y
}]),
onPanResponderGrant: (evt, gestureState) => {
console.log(evt)
},
onPanResponderRelease: (e, gesture) => {
// console.log(e)
if (this.isDropZoneCar(gesture)) {
ToastAndroid.show('Correct', ToastAndroid.SHORT);
} else {
ToastAndroid.show('Wrong', ToastAndroid.SHORT);
}
}
});
}
isDropZoneCar(gesture) {
var dz = this.state.dropZoneCar;
return gesture.moveY > dz.y && gesture.moveY < dz.y + dz.height;
}
setDropZoneCar(event) {
this.setState({
dropZoneCar: event.nativeEvent.layout
});
}
setDropZoneBike(event) {
this.setState({
dropZoneBike: event.nativeEvent.layout
});
}
render() {
return (
<View style={styles.mainContainer}>
<View style={{ flexDirection: 'row', }}>
<View style={{ flex: 1 }}>
<View
onLayout={this.setDropZoneCar.bind(this)}
style={[styles.dropZone, { backgroundColor: this.state.disableCar ? 'green' : '#2c3e50' }]}>
<Text style={styles.text}>Drop a Car</Text>
</View>
<View
onLayout={this.setDropZoneBike.bind(this)}
style={[styles.dropZone, { backgroundColor: this.state.disableCar ? 'green' : '#2c3e50' }]}>
<Text style={styles.text}>Drop a Bike</Text>
</View>
</View>
<View style={{ flex: 1 }}>
{this.draggableCar()}
</View>
</View>
</View>
);
}
draggableCar() {
return (
<View style={styles.draggableContainer} >
<Animated.View
{...this.panResponderCar.panHandlers}
style={[this.state.panCar.getLayout()]}>
<Image
style={{ position: "absolute", width: 200, height: 100, right: 10, top: 300, }}
source={require('./assets/carr.png')}
/>
</Animated.View>
</View>
);
}
}
let CIRCLE_RADIUS = 36;
let Window = Dimensions.get('window');
let styles = StyleSheet.create({
mainContainer: {
flex: 1
},
dropZone: {
height: 100,
backgroundColor: '#2c3e50',
marginTop: 100
},
text: {
marginTop: 25,
marginLeft: 5,
marginRight: 5,
textAlign: 'center',
color: '#fff'
},
draggableContainer: {
position: 'absolute',
top: Window.height / 2 - CIRCLE_RADIUS,
left: Window.width / 2 - CIRCLE_RADIUS,
},
});
You are listening to the delta of the finger movement dx and dy, so whenever you touch again, your pan values drop to 0's. You should set an offset on your pan values every time you touch to fix this. Add this piece of code:
onPanResponderGrant: (e, gestureState) => {
this.state.panCar.setOffset({x: this.state.panCar.x._value, y: this.state.panCar.y._value});
this.state.panCar.setValue({x: 0, y: 0});
}
This will set the offset for your pan to current position, so it doesn't jump back after consequent touches. Hope this helps.

Animation and flex space-between layout

I have 3 blocks disposed using justifyContent: 'space-between'.
The bottom block should be animated (bounce in loop) in height for 100 units in the grey area. The problem is I can't edit margins of the bottom block because justifyContent prop causes the middle block moves (first and middle block should be fixed).
import React, { Component } from 'react';
import { StyleSheet, Text, View, Easing, Animated, // Button,
ScrollView } from 'react-native';
import Button from 'react-native-button';
export default class App extends Component {
constructor () {
super()
this.animatedValue = new Animated.Value(0)
this.animate(Easing.bounce)
}
animate (easing) {
this.animatedValue.setValue(0)
Animated.timing(
this.animatedValue,
{
toValue: 1,
duration: 1000,
easing
}
).start( ()=> this.animate(Easing.bounce))
}
render () {
const marginBottom = this.animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [0, 100]
})
return (
<View style={{flex: 1,flexDirection: 'column',alignItems:"center",justifyContent: 'space-between' }}>
<View style={styles.block}><Text>top</Text></View>
<View style={styles.block}>><Text>second</Text></View>
<View style={{textAlign: "center",height:150,backgroundColor:"#555"}}>
<Animated.View style={[styles.block2, {marginBottom} ]}>
<Text style={{position:"absolute"}} >bottom</Text>
</Animated.View>
</View>
</View>
);
}
}
var styles = StyleSheet.create({
block: {
width: 50,
height: 50,
backgroundColor: 'red',
},
block2: {
width: 50,
height: 50,
backgroundColor: 'red',
}
});
https://snack.expo.io/#alfredopacino/animations-easing
To be more clear about what I'm trying to accomplish. It is just this plain and simple animation https://drive.google.com/open?id=1_nunJMjdsAkjvbE4_URc4GIsoDw8M7KN
Just change your marginBottom to marginTop
<View style={{ textAlign: "center", height: 150, backgroundColor: "#555" }}>
<Animated.View style={[styles.block2, { marginTop:marginBottom }]}>//<-changes--
<Text style={{ position: "absolute" }}>bottom</Text>
</Animated.View>
</View>

React Native Flatlist overlapping footer?

I'm getting started with React Native and writing an app. The problem I'm having a problem with the layout/styling. This is a simplified version to show my difficulty.
The Flatlist doesn't know where it's bottom is, it is overlapping the Footer component. I've messed around with it but can't get it to work properly.
import React, { Component } from 'react'
import { FlatList, StyleSheet, Text, View } from 'react-native'
class Header extends Component {
render() {
return (
<View style={styles.headerContainer}>
<Text style={styles.headerText}> </Text>
<Text style={styles.headerText}>
This is the page header!
</Text>
</View>
)
}
}
class Footer extends Component {
render() {
return (
<View style={styles.footerContainer}>
<Text style={styles.footerText}>
This is the page footer!
</Text>
</View>
)
}
}
let myData = [];
for (let i=1; i<=30; i++) {
myData.push({ key: ('My item ' + i) })
}
export default class App extends Component {
render() {
return (
<View style={styles.container}>
<Header />
<View style={styles.listWrapper}>
<FlatList
contentContainerStyle={styles.listContainer}
data={myData}
renderItem={({item}) => <Text style={styles.listItem} >{item.key}</Text>}
contentInset={{top: 0, left: 0, bottom: 50, right: 0}}
/>
</View>
<Footer />
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'pink'
},
headerContainer: {
backgroundColor: '#333',
height: 60,
},
headerText: {
textAlign: 'center',
fontSize: 20,
color: '#999'
},
listWrapper: {
flex: 1
},
listContainer: {
backgroundColor: 'lightblue',
},
listItem: {
color: 'red',
fontSize: 28
},
footerContainer: {
backgroundColor: '#333',
position: 'absolute',
left: 0,
right: 0,
bottom: 0,
flex: 1,
height: 20
},
footerText: {
textAlign: 'center',
fontSize: 14,
color: '#999'
}
})
The only solution I have is to add the prop:
ListFooterComponent={<View style={{ height: 20 }} />}
to the Flatlist, giving it the same height as the Footer, so it would take up that space. That works, but it seems inelegant. Is there a better way to do it, like with the CSS?
Thanx.

Using react-native-camera, how to access saved pictures?

My goal is to use the react-native-camera and simply show a picture on the same screen, if a picture has been taken. I'm trying to save the picture source as "imageURI". If it exists, I want to show it, if a picture hasn't been taken yet, just show text saying No Image Yet. I've got the camera working, since I can trace the app is saving pictures to the disk. Having trouble with the following:
How to assign the capture functions data to a variable when I take the picture, that I can call later (imageURI).
Don't know how to do an if statement in Javascript to check if a variable exists yet.
import Camera from 'react-native-camera';
export default class camerahere extends Component {
_takePicture () {
this.camera.capture((err, data) => {
if (err) return;
imageURI = data;
});
}
render() {
if ( typeof imageURI == undefined) {
image = <Text> No Image Yet </Text>
} else {
image = <Image source={{uri: imageURI, isStatic:true}}
style={{width: 100, height: 100}} />
}
return (
<View style={styles.container}>
<Camera
captureTarget={Camera.constants.CaptureTarget.disk}
ref={(cam) => {
this.camera = cam;
}}
style={styles.preview}
aspect={Camera.constants.Aspect.fill}>
{button}
<TouchableHighlight onPress={this._takePicture.bind(this)}>
<View style={{height:50,width:50,backgroundColor:"pink"}}></View>
</TouchableHighlight>
</Camera>
I found the answer to my own question. This is an example of the react-native-camera being used.
https://github.com/spencercarli/react-native-snapchat-clone/blob/master/app/routes/Camera.js
Found this answer in another earlier posted question answered by #vinayr. Thanks!
Get recently clicked image from camera on image view in react-native
Here's the code from the first link:
import React, { Component } from 'react';
import {
View,
StyleSheet,
Dimensions,
TouchableHighlight,
Image,
Text,
} from 'react-native';
import Camera from 'react-native-camera';
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#000',
},
preview: {
flex: 1,
justifyContent: 'flex-end',
alignItems: 'center',
height: Dimensions.get('window').height,
width: Dimensions.get('window').width
},
capture: {
width: 70,
height: 70,
borderRadius: 35,
borderWidth: 5,
borderColor: '#FFF',
marginBottom: 15,
},
cancel: {
position: 'absolute',
right: 20,
top: 20,
backgroundColor: 'transparent',
color: '#FFF',
fontWeight: '600',
fontSize: 17,
}
});
class CameraRoute extends Component {
constructor(props) {
super(props);
this.state = {
path: null,
};
}
takePicture() {
this.camera.capture()
.then((data) => {
console.log(data);
this.setState({ path: data.path })
})
.catch(err => console.error(err));
}
renderCamera() {
return (
<Camera
ref={(cam) => {
this.camera = cam;
}}
style={styles.preview}
aspect={Camera.constants.Aspect.fill}
captureTarget={Camera.constants.CaptureTarget.disk}
>
<TouchableHighlight
style={styles.capture}
onPress={this.takePicture.bind(this)}
underlayColor="rgba(255, 255, 255, 0.5)"
>
<View />
</TouchableHighlight>
</Camera>
);
}
renderImage() {
return (
<View>
<Image
source={{ uri: this.state.path }}
style={styles.preview}
/>
<Text
style={styles.cancel}
onPress={() => this.setState({ path: null })}
>Cancel
</Text>
</View>
);
}
render() {
return (
<View style={styles.container}>
{this.state.path ? this.renderImage() : this.renderCamera()}
</View>
);
}
};
export default CameraRoute;

Make React Native Modal appear from top to bottom

I noticed that the Modal component's animationType property only allows for it to slide from bottom to top. How could I change the animation and make the modal appear from top to bottom?
Thanks for your time.
It doesn't look like that component allows for that type of configuration.
One thing you could do is use the Animated library to create your own modal. You would set the translateY property to negative of of the height of the device, then animate the translateY value to 0:
openModal() {
Animated.timing(this.state.modalY, {
duration: 300,
toValue: 0
}).start();
},
closeModal() {
Animated.timing(this.state.modalY, {
duration: 300,
toValue: -deviceHeight
}).start();
},
A full implementation is below:
'use strict';
var React = require('react-native');
var {
AppRegistry,
StyleSheet,
Text,
View,
TouchableHighlight,
Animated,
Dimensions
} = React;
let deviceHeight = Dimensions.get('window').height
var deviceWidth = Dimensions.get('window').width
var SampleApp = React.createClass({
openModal() {
Animated.timing(this.state.modalY, {
duration: 300,
toValue: 0
}).start();
},
closeModal() {
Animated.timing(this.state.modalY, {
duration: 300,
toValue: -deviceHeight
}).start();
},
getInitialState(){
return {
modalY: new Animated.Value(-deviceHeight)
}
},
render() {
var Modal = <Animated.View style={[ styles.modal, { transform: [ {translateY: this.state.modalY}] }]}>
<TouchableHighlight onPress={ this.closeModal } underlayColor="green" style={ styles.button }>
<Text style={ styles.buttonText }>Close Modal</Text>
</TouchableHighlight>
</Animated.View>
return (
<View style={styles.container}>
<TouchableHighlight onPress={ this.openModal } underlayColor="green" style={ styles.button }>
<Text style={ styles.buttonText }>Show Modal</Text>
</TouchableHighlight>
{ Modal }
</View>
);
}
});
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center'
},
button: {
backgroundColor: 'green',
alignItems: 'center',
height: 60,
justifyContent: 'center',
},
buttonText: {
color: 'white'
},
modal: {
height: deviceHeight,
width: deviceWidth,
position: 'absolute',
top:0,
left:0,
backgroundColor: '#ededed',
justifyContent: 'center',
}
});
AppRegistry.registerComponent('SampleApp', () => SampleApp);
Use react-native-modal community package. It has built in this feature. Set animationIn={'slideInDown'}, animationInTiming={300} properties.