Move Xposition of View from 0 to its origianl position in React Native - react-native

const valueX = useRef(new Animated.Value(0)).current
useEffect(() => {
Animated.timing( valueX , {
toValue : // How to get the original X position of the component here.
duration : 1000,
easing : Easing.linear
}).start()
}, [])
So, I have a component (i.e View) originally at some position on the screen. I wanted to have a slight animation there using react native animated API. What I want is to move X position of that view from 0 to its original position . How can it be done?

I guess you need the position of the element - set that as your state and then change it in the way you want. Check out this question to get the elements position.
React Native: Getting the position of an element

Related

Is there a way to animate the increased size of a View when new children are added?

I’m currently using LayoutAnimation to animate a view when children are added. However, since LayoutAnimation causes everything to be animated, globally, and I can’t easily use built-in Animated library to fit my use-case, I’m wondering if react-native-reanimated is able to help.
Here's a snack of my current solution:
https://snack.expo.io/#insats/height-adapation
This is what the result of that looks like:
Is there a way to achieve the same thing without using LayoutAnimation? I've looked through all exampled in react-native-reanimated, and I've read through the docs but I'm still not sure if this is possible to do or how I should get started. I've thought about using Animated to move the item-wrapper out of the viewable area and "scroll" it upwards (using transform translateY) when items are added, but that would require fixed height, which I don't have.
I have 2 approaches that I can suggest out of my mind:
You can configure your LayoutAnimation only when your desired state changed. If you use hooks it would be too easy:
const [state,setState] = useState([]);
useEffect(()=>{
/*rest code*/
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
},[state])
Or if you use class component you can catch your desired state change in componentDidUpdate:
componentDidUpdate(prevProps,prevState){
if(prevState.items!==state.items){
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
}
}
You can use onLayout function of view:
addItem = () => {
this.setState({
items: [...this.state.items, {title:'An item',isNew:true}]
})
};
renderItems = () => {
return this.state.items.map((item, index) => {
let opacity = new Animated.Value(0);
return (
<Animated.View onLayout={({nativeEvent})=>{
if(this.state.item.isNew){
// here you got the height from nativeEvent.layout.height
// Then you have to store the height animate height and opacity to its precise value
// PS I used opacity:0 to calculate the height
}
}} key={index} style={[styles.item,{opacity}>
<Text>{item.title}</Text>
</View>
)
});
};
When it comes to react-native-reanimated I regard it as more faster version of react-native's Animated library. So either way you will have to calculate the height!

React Native state update during animation "resets" the animation

I am facing a problem that I've tried to solve in lots of different ways, but I cannot get it to work. Please see this Expo application, I've created a dumb example that demonstrates my problem: https://snack.expo.io/HJB0sE4jS
To summarize, I want to build an app with a draggable component (The blue dot in the example), but while the user drags the component I also need to update the state of the app (the counter in the example). The problem is that whenever the state updates during dragging, the component resets to it's initial position. I want to allow the user to freely drag the component while state updates happen.
I was able to "solve" the issue by putting the PanResponder in a useRef, so it won't be reinitialized in case of a state update, but as you can see in the example, I want to use the state in the PanResponder. If I put it in a useRef I cannot use the state in the PanResponder because it will contain a stale value (it will always contain the initial value of the counter which is 0).
How do you handle these kind of situations in react native? I guess it is not too uncommon that someone wants to update the state during an animation, although I cannot find any documentation or examples on this.
What am I doing wrong?
Edit: I was investigating further and I can see that the problem is that I'm mapping the (dx,dy) values from the gesture parameter to the position, but the (dx,dy) values are reset to (0,0) when the state changes. I guess (dx,dy) initialized to (0,0) when PanResponder is created. Still don't know what to do to make this work...
A mutable ref that holds the latest counter state value, along with a ref to prevent re-initializing the PanResponder should solve the problem in the example:
const [counter] = useCounter();
// Update the counterValue ref whenever the counter state changes
const counterValue = useRef(counter);
useEffect(() => {
counterValue.current = counter;
}, [counter]);
const position = useRef(new Animated.ValueXY());
const panResponder = useRef(PanResponder.create({
onStartShouldSetPanResponder: () => true,
onPanResponderMove: Animated.event(
[null, { dx: position.current.x, dy: position.current.y }],
{ listener: () => console.log(counterValue.current) } // counterValue being a ref, will not go stale
),
onPanResponderRelease: () => {
Animated.spring(position.current, { toValue: { x: 0, y: 0 } }).start();
}
})
);
You can check the above suggestion here: https://snack.expo.io/rkMLgp4jB
I understand though that this is a rather simplified example, and may not work for your actual use-case. It would help if you could share some more details on the actual usage!

React Native Animated.Value/Animated.timing without Animated.View

I have some state variables I want to animate for user micro-interaction. These variables are not properties of a view or style properties; they are actually properties of an SVG such as Circle radius (using react-native-svg). I have used window.requestAnimationFrame to animate these circles and it works buttery smooth but I would like to get features of React.Animated and Easing and maybe reduce some code if this is possible.
So I am struggling with getting Animated.timing(...).start() to update my state for each frame so the rendering will occur.
In an event handler I have something like:
let radiusValue = new Animated.Value(0);
this.setState({ holding: {
radius: radiusValue,
animator: Animated.timing(
radiusValue,
{
toValue: closest.radius*1.15,
duration: 1,
easing: Easing.bounce(3)
}
).start(() => console.log("done"))
}
So that sets up the animation. Now somewhere in my render() code I have:
<Animated.View>
<Svg><Circle cx={x} cy={y} radius={this.state.radius._value}</Svg>
</Animated.View>
Now because my radius Animated.Value is not part of Animated.View props I guess it doesnt generate tween frames. I do get the "done" message from within the Animated.timing(..).start(callback) but obviously since nothing is directly wired up to modifying my state I don't get calls to render for tweening. So how do I get the Animated.timing() to modify my state?
I've tried converting the Svg to an Animated control but this actually crashes the iOS Simulator to home screen (no red screen exception error).
let AnimatedSvg = Animated.createAnimatedControl(Svg);
...
<AnimatedSvg><Circle cx={x} cy={y} radius={this.state.radius._value}</AnimatedSvg>
Is there a callback from Animated.timing(...) that I could set to then call setState()?
The code above is very pseudo, trying to keep the question light.

React native synchronize two flatlist smoothly

I have two flatlist, one contains the data (dataScroll) and the other the checkboxes (checkScroll) for every data item.
The reason for this is that the checkboxes have to be always visible while the user scrolls horizontaly on the dataScroll (I put the dataScroll in a horizontally scrollable scrollview).
Demo:
expo snack demo
Tried so far:
On dataScroll's scroll event, I got the y offset and moved the checkScroll to that y position.
handleDataScroll = ({ nativeEvent: { contentOffset: { y } } }) => {
this.checkScroll.scrollToOffset({ offset: y, animated: true });
}
It (almost) does the job, but there is a huge delay between the 2 flatlist while scrolling.
--
I read that maybe the use of animated components the way to go, but I couldn't figure out how the animation works in react native.
So I'd like to get some help on how should I bind the two flatlist together so that if I scroll on one list, the other follows it with no (or at least minimal) delay.
If only the dataScroll flatlist is scrollable that's ok too.

How to find x,y position of Component in React native

How do I find out the x,y position of where an element is positioned on the screen, I'm using React Native v0.14. I have tried the following but it says measure is not a function.
componentDidMount() {
setTimeout(this.measurePosition);
},
measurePosition() {
this.refs.q.measure((a, b, width, height, px,py ) => console.log(width))
},
Option1:
You can use the NativeMethodsMixin. Make sure you've added the mixin to your class
var NativeMethodsMixin = require('NativeMethodsMixin')
...
var MyComponent = React.createClass({
mixins: [NativeMethodsMixin]
...
componentDidMount: function(){
this.refs.element.measure((x,y,w,h,pX,pY) => console.log("dets"))
}
Option 2
You can use the onLayout property on Views. It is available on most components.
render:function(){
...
<View onLayout = {this.onLayout} />
...
},
onLayout:function(event){
console.log(event.nativeEvent.layout)
}
You will get the x,y, width and height
Can you use something like
1. get the browser DOM element using (ReactDOM.findDOMNode())
2. Use the elements getBoundingClientRect()
3. You have top, left, bottom and right coords
this may also be useful Retrieve the position (X,Y) of an HTML element