How should I animate a React native component with the library "Animated" - react-native

I'm trying to animate some component. I Just want to change the size of the width of a View. I'm been looking the simplest way to make simple animations.I'm using the library "Animated".I can't make this work
I'm looking for some tutorials and it doesn't work.For some reason the code doesn't reconize the initial width of a "Animated.View" it is a variable declarated on the constructor just like this "animationwidth = new Animated.Value(11);".I dont know if the problem is in the declaration of the variable, in the style of the "Animated.View"or in the "animated.timing" function
import React, { Component } from 'react';
import {Animated,Text,Alert,View, Image, Button} from 'react-native';
export default class Game extends Component {
constructor(props) {
super(props);
this.state = {
opa: 1
};
animationwidth = new Animated.Value(11);
}
componentDidmount(){
Animated.timing(this.animationwidth, {
toValue: 300
}).start()
}
render(){
return(
<View style={{flex:1,alignItems:'center',backgroundColor:'green',justifyContent:'center'}}>
<Animated.View style={{ height:250, width:this.animationwidth ,backgroundColor:'blue'}}/>
</View>
)
}
}

You forgot to include state to animationwidth:
change your Animated.View component style like this:
<Animated.View style={{ height:250, width:this.state.animationwidth ,backgroundColor:'blue'}}/>
if does not animate. add duration property inside Animated timing function and also add state to animationwidth like this :
Animated.timing(this.state.animationwidth, {
toValue: 300,
duration: 1000
}).start()
}
base on your code the width of your View will start at 11 and end with 300

The problem here is the render method not called again as the state is not updated again. You need to update some state variable in componentDidmount and thus the render method will call again.
Add a state variable and toggle that variable in componentDidMount
this.state = {
isShowing : false
};
componentDidmount(){
this.setState({isShowing:!this.state.isShowing})
Animated.timing(this.animationwidth, {
toValue: 300
}).start()
}

Related

How can I implement animation in my flatlist?

I am using Flatlist in my rn project and when I push new data into my flatlist, my item 1 will automatically move from position A to position B. But my question is I don't want it to just change the position, I want to use animation to move my item(from position A to position B). How can I implement that? Thank you!
Please check the demo picture and video from the link down below:
https://photos.app.goo.gl/WypswNyA38A2EAPQA
https://photos.app.goo.gl/Ev1RYMduDj7mxrHn7
You can use Animated component to do the animation. As per your attached video, 2 steps animation comes into play, one which pushes the items up in the list and another one which increases the opacity of the list item. A simple approach would be to add the list item with height 0 and increase the height to desired height using animation, this will complete the first step. Once the first step is completed, control the opacity to go from 0 to 1.
Next, you need to start the animation when the list item is added to the list, componentDidMount is the right place to do so. Please consider the following component which does the above steps.
import React from 'react';
import { Animated } from 'react-native';
class AnimatedListItem extends React.Component {
constructor(...props) {
super(...props);
this.state = {
height: new Animated.Value(0),
opacity: new Animated.Value(0)
};
}
componentDidMount() {
Animated.sequence([
Animated.timing(
this.state.height,
{
toValue: this.props.height,
duration: this.props.duration || 1000
}
),
Animated.timing(
this.state.opacity,
{
toValue: 1,
duration: this.props.duration || 1000
}
)
]).start();
}
render() {
const { height, opacity } = this.state;
return (
<Animated.View
style={{
...this.props.style,
height: height,
opacity: opacity
}}
>
{this.props.children}
</Animated.View>
);
}
}
export default AnimatedListItem;
In the above snippet, two animations are passed to Animated.sequence([...]) method to animate one after the other.
You can now use the above component in the renderItem method like
renderItem = () => {
return (
<AnimatedListItem height={50} duration={800} style={...}>
/* render actual component here */
</AnimatedListItem>
);
}
Hope this will help!
Note: This is a bare minimum example to achieve what you are looking for.

Using Fade-in Animation from #shoutem/animation on s3 image

I am displaying my images from S3. I would like them to fade-in on load. This seems like it should be a simple request. Can someone give me some guidance on this, if possible?
Thanks!
You can just use a TimingDriver to animate the component.
import React from 'react';
import { View, Easing } from 'react-native';
import { TimingDriver, FadeIn } from '#shoutem/animation';
class Screen extends React.Component {
render() {
driver = new TimingDriver({
duration: 400 // 250 by default,
easing: Easing.inOut // Easing.cubic is passed by default
delay: 0 // 0 by default
});
return (
<View>
<FadeIn driver={driver}>
{/* Some components to fade in with time passing */}
</FadeIn>
</View>
)
}
}
You can find out more about the Animation part of the toolkit here.

react-native scrollView - scrollToEnd - on Android

I'm trying to call a function that will fire upon onFoucs on TextInput that will scroll the scrollView all the way down (using scrollToEnd())
so this is my class component
class MyCMP extends Component {
constructor(props) {
super(props);
this.onInputFocus = this.onInputFocus.bind(this);
}
onInputFocus() {
setTimeout(() => {
this.refs.scroll.scrollToEnd();
console.log('done scrolling');
}, 1);
}
render() {
return (
<View>
<ScrollView ref="scroll">
{ /* items */ }
</ScrollView>
<TextInput onFocus={this.onInputFocus} />
</View>
);
}
}
export default MyCMP;
the component above works and it does scroll but it takes a lot of time ... I'm using setTimeout because without it its just going down the screen without calculating the keybaord's height so it not scrolling down enough, even when I keep typing (and triggering that focus on the input) it still doesn't scroll all the way down.
I'm dealing with it some good hours now, I did set the windowSoftInputMode to adjustResize and I did went through some modules like react-native-keyboard-aware-scroll-view or react-native-auto-scroll but none of them really does the work as I need it.
any direction how to make it done the right way would be really appreciated. thanks!
Rather than using a setTimeout you use Keyboard API of react-native. You add an event listener for keyboard show and then scroll the view to end. You might need to create some logic on which input is focused if you have more than one input in your component but if you only have one you can just do it like the example below.
Another good thing to do is changing your refs to functional ones since string refs are considered as legacy and will be removed in future releases of react. More info here.
class MyCMP extends Component {
constructor(props) {
super(props);
this.scroll = null;
this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this._keyboardDidShow.bind(this));
}
componentWillUnmount () {
this.keyboardDidShowListener.remove();
}
_keyboardDidShow() {
this.scroll.scrollToEnd();
}
render() {
return (
<View>
<ScrollView ref={(scroll) => {this.scroll = scroll;}}>
{ /* items */ }
</ScrollView>
<TextInput />
</View>
);
}
}
export default MyCMP;
If you have a large dataset React Native docs is telling you to go with FlatList.
To get it to scroll to bottom this is what worked for me
<FlatList
ref={ref => (this.scrollView = ref)}
onContentSizeChange={() => {
this.scrollView.scrollToEnd({ animated: true, index: -1 }, 200);
}}
/>

New animation after setState - React Native

I don't find the answer to my problem for my react native app.
If you have an idea how to achieve that, that would be great :)
What I'm trying to do:
In a page, when I press somewhere, I want to display an animation (for example a square apparition) on the press position.
What I have achieved:
When I click, a square is display with an animation on the right position.
But when i click somewhere else, The position of the square changes but the animation doesn't restart.
What I have tried:
To do the animation, I place a < View/> (with position: 'absolute') on the press position.
This < View/> is embeded in a component that I call 1 time in my App render:
<ClickAnimation x={item.x} y={item.y}/>
where item.x and item.y are are the coordinate.
This is the code of my component:
import React from 'react';
import {Animated, View} from 'react-native';
export default class ClickAnimation extends React.Component {
state = {
scaleAnim: new Animated.Value(0)
};
componentWillMount() {
Animated
.timing(this.state.scaleAnim, {
toValue: 2,
duration: 500
})
.start();
}
componentWillUpdate(nextProps) {
if (nextProps.x != this.props.x && nextProps.y != this.props.y) {
this.setState({
scaleAnim: new Animated.Value(0)
})
}
}
componentDidUpdate() {
console.log("componentDidUpdate",this.state.scaleAnim)
Animated
.timing(this.state.scaleAnim, {
toValue: 2,
duration: 500
})
.start();
}
render() {
return (<Animated.View
style={{
position: "absolute",
top: this.props.y,
left: this.props.x,
width: 50,
height: 50,
backgroundColor: "red",
transform: [
{
scaleY: this.state.scaleAnim
}, {
scaleX: this.state.scaleAnim
}, {
translateX: -25
}, {
translateY: -25
}
]
}}/>);
}
}
The console.log in componentDidUpdate give me for each click 2 logs:
{_children: Array(2), _value: 2, ..., _animation: null…}
{_children: Array(2), _value: 0,..., _animation: null…}
I really don't know what to do next.
PS: In NativeScript, that was more easy. I had just to add the new component to the DOM.
According to React docs you cannot this.setState() inside componentWillUpdate(),if you need to update state in response to a prop change, use componentWillReceiveProps(nextProps) instead.
https://facebook.github.io/react/docs/react-component.html#componentwillreceiveprops
Read the above link for more details on that and check its caveats.
I hope this is what is causing the problem
It seems that EXPO XDE make the application too slow and this is why the animation part doesn't work properly.
I have found the solution.
This come with this issue:
https://github.com/facebook/react-native/issues/6278
I had seen it and this is why I wrote first 0,001. But 0,001 is still to little. With 0,01 it works great.
So the answer is:
Just replace 0 by 0.01 because it was too little.

React Native: Updating state in onLayout gives "Warning: setState(...): Cannot update during an existing state transition"

I have a component in React Native which updates it's state once it knows what size it is.
Example:
class MyComponent extends Component {
...
render() {
...
return (
<View onLayout={this.onLayout.bind(this)}>
<Image source={this.state.imageSource} />
</View>
);
}
onLayout(event) {
...
this.setState({
imageSource: newImageSource
});
}
...
}
This gives the following error:
Warning: setState(...): Cannot update during an existing state transition (such as within render or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to componentWillMount.
I guess the onLayout function is called while still rendering (which can be good, the sooner the update, the better). What is the correct way to solve this problem?
Thanks in advance!
We got around this by using the measure function, you will have to wait until the scene is fully complete before measuring to prevent incorrect values (i.e. in componentDidMount/componentDidUpdate). Here's an example:
measureComponent = () => {
if (this.refs.exampleRef) {
this.refs.exampleRef.measure(this._logLargestSize);
}
}
_logLargestSize = (ox, oy, width, height, px, py) => {
if (height > this.state.measureState) {
this.setState({measureState:height});
}
}
render() {
return (
<View ref = 'exampleRef' style = {{minHeight: this.props.minFeedbackSize}}/>
);
}
Here is a solution from documentation for such cases
class MyComponent extends Component {
...
render() {
...
return (
<View>
<Image ref="image" source={this.state.imageSource} />
</View>
);
}
componentDidMount() {
//Now you can get your component from this.refs.image
}
...
}
But for my opinion it's better to do such things onload