How to use animation multiple times in framer motion - javascript

Just like in the title, I'm trying to animate my component multiple times when clicking a button. Currently, animation only runs once and then it doesn't work anymore, how could I possibly implement that
here is an example of what I'm trying to do:
const controls = useAnimation();
const handleClick = (e) => {
controls.start({
rotate: "360deg",
});
};
return(
<motion.button onClick={handleClick}>Button</motion.button>
<motion.div className="someRect" animate={controls}></motion.div>
)

To be honest, I've never worked with useAnimation controls so I have no idea what's going on here and how to come around this obstacle using your approach, but you may achieve what you are after with something like this.
<button onClick={() => setRotate((prevState) => prevState + 360)}>
Button
</button>
<motion.div
className="someRect"
animate={{
rotate: rotate,
transition: { duration: 3 }
}}
style={{ width: "100px", height: "100px", background: "red" }}
>
</motion.div>
I know that this solution is not optimal as the state is growing and growing with each click to possibly very substantial size which may cause problems at some point.
Check my solution in this CodeSanbox
Hope maybe someone will come up with a much more elegant solution which I'd appreciate seeing too.

Related

Prevent useState rerendering animation

I have set up a realtime firebase that detects user joining my site. When they join, I add them to my useState variable and then display them on the map. I use framer motion to create a simple animation.
The problem is that when a user gets added, removed, or modified that user gets animated, and all the other users get animated again as well. I have tried to use React.memo, with no success. Maybe I am just using it wrong or there is another solution that I can't come up with yet.
const [onlineUsers, setOnlineUsers] = useState([]);
{onlineUsers?.map((user) => (
<motion.g
initial={{ scale: 0 }}
animate={{ rotate: 0, scale: 1 }}
transition={{
type: 'spring',
stiffness: 260,
damping: 20,
}}
>
<image
width='12'
height='12'
href={UserImage}
/>
</motion.g>
))}
Framer motion detect animate from key attribute, set unique key to each iterated element.
How useState and useMemo works? Every time an element changes, it will re-render the whole component. As you are storing all users in onlineUsers, once you modified onlineUsers will re-render your variable (all elements inside your variable). Check this example

How to: Animate 9gag's "add button" by using React Native

So I wanted to challange myself and try to implement the blue button from 9gag which allows you to add content. Its on the right bottom cornern and every time you scroll down and reach a specific "speed" it disappears. And when you scroll up again, it appears again until you scroll down again with that specific "speed". I tried my best but couldnt make it. Here is the link to the video how it should look:
https://www.youtube.com/watch?v=ieT4hZJST5I&feature=youtu.be
So far I was able to make that button on the right postion. But I dont know how to change his visibility onScroll:
<TouchableOpacity
activeOpacity={0.6}
style={{
position: 'absolute',
right: addContentButtonRight,
bottom: addContentButtonBottom,
opacity: addContentButtonOpacity
}}
// onPress={this.onAddPress}
>
<Image style={{width: 65, height: 65}} source={iconSource} />
</TouchableOpacity>
And this here is what was my idea for it:
//using state to be able to update opacity
const [addContentButtonOpacity, setAddContentButtonOpacity] = useState(1);
//when the scrollView is scrolled I would call this function with onScroll().
//It sets the new value to opacity by using opacity - 0.1
//In this way the further you scroll, the more invisible it bacomes
const addContentButtonOpacityChange = () => {
setAddContentButtonOpacity(addContentButtonOpacity-0.1);
}
And also if this would work and my button becomes invisible, how would I make it not touchable so that the invisable button cant be clicked by mistake/randomly?
Any idea how to implement this?

How to rebuild the iOS Picker animation in React Native

Is there a way in React Native to rebuild the iOS picker component completely in Java Script? I don't need the common picker, but a normal scroll view with a similar fade-out effect like the iOS picker.
EDIT – I think I have not explained my initial answer exactly enough. This is why I complete it here:
I want to build a scroll view that takes over the whole screen. It's not supposed to give the user the possibility to elect some item, like the the iOS Picker does. Nevertheless, it's supposed to be a 'normal' scroll view, that shows the user some information, e.g. different chats, tasks, news and so on.
The only difference to React Native's common scroll view should be the fade-out effect at the top: When the user scrolls the content up, it should not just leave the screen at its top edge, but it should use the iOS Picker's fade-out effect (see picture).
This fade-out effect is made up of two parts: First of all, it raises the content's transparency with a decreasing y-coordinate. Furthermore, this content seems to escape into the third dimension.
My problem is, that I don't see a way to achieve this three-dimensionality of the content in React Native. I've to add, that the content in my scroll view does not consist of small, equally sized items (like e.g. the texts 'Item 1', 'Item 2', 'Item 3',...), but of bigger items with different sizes like images or whole textboxes.
You can use this NPM module to get what you want. That module works the same in Android and iOS. Do not reinvent the wheel :)
EDIT: Now I've understood what you want. You can try this snack that I've made for you:
https://snack.expo.io/r1qnxSt9m
Of course you need to improve it, but it's a beginning.
You can achieve the desired effect with the Animated api. The idea is to set different input ranges to the items in your list. You then hook the opacity to the scroll value of your ScrollView (or any list component). I have simplified the code, but it should be enough to demonstrate the idea.
The example below only demonstrates an opacity effect, but you could easily add a translate effect to get the exact animation that you are looking for.
const data = []; // array that contains the text
const items = [];
for (let i = 0; i < data.length; ++i) {
const distanceFromViewCenter = Math.abs(i * ITEM_HEIGHT);
const inputRange = [
-distanceFromViewCenter - 2 * ITEM_HEIGHT,
-distanceFromViewCenter - ITEM_HEIGHT,
-distanceFromViewCenter, // Middle of picker
-distanceFromViewCenter + ITEM_HEIGHT,
-distanceFromViewCenter + 2 * ITEM_HEIGHT,
];
items.push(
<Animated.View
style={{
opacity: this._scrollValue.interpolate({
inputRange,
outputRange: [0.0, 0.3, 1.0, 0.3, 0.0],
}),
}}
>
<Text style={{ height: ITEM_HEIGHT }}>{data[i]}</Text>
</Animated.View>
)
}
<ScrollView
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { y: this._scrollValue } } }],
{ useNativeDriver: true }
)}
>
{items}
</ScrollView>

GSAP: Accordion children animation

I've been trying to create something along the lines of accordion component in React, (the code pen is in vanilla but demonstrates the problem).
Pen: https://codepen.io/tim-bitanov/pen/MXrVRE
Original issue:
Basically, the accordion changes its width when expanded and items begin to enter from below. My problem is that the items do not really come from below, but rather from bottom right since the left property of the container changing due to new width.
<TransitionGroup component={null}>
{this.props.expanded && (
React.Children.map(this.props.children, (child) => (
<Transition
timeout={500}
onEnter={this.onSubMenuEnter}
onExit={this.onSubMenuExit}
>
{child}
</Transition>
)))}
</TransitionGroup>
private onSubMenuEnter = (node: HTMLElement) => {
TweenLite.set(node, { clearProps: 'all' });
TweenLite.from(node, .5, { y: '+=50', opacity: 0 });
}
Can anyone suggest any way to tackle this?
I've tried using the TweenMax.ticker to get current parent left property but was unsure what to do with it
If you're still looking for a solution or someone else I forked your pen to make the items come from below.
You basically just need to translate them from half the width you're expanding the parent as long as you're using the same animation duration and easing.
see below for a container expanding from 0 to 130 as in your demo
TweenMax.from(items, 1, {y: '+=50'}); //not ok
TweenMax.from(items, 1, {y: '+=50', x:'-=65'}); //ok
The forked pen demo

How to make different animations on same page independantly start on hover and go to original state upon mouseleave with JQuery Animate

Ok I search everywhere but I just cant find the answer to my question.
I have many CSS3 transitions and animations and actually want to implement them for internet explorer 8-9. However im pretty much a newcomer with javascript.
First this is my website http://tinyurl.com/axjuccx you will see the css animations used.
Now, what im trying to achieve is the same but with Jquery animate() function.
As an example lets take this piece of code where I animate a div called block upon hovering over a button called go.
$("#go").mouseenter(function(){
$("#block").animate({
width: "70%",
opacity: 0.4,
marginLeft: "0.6in",
fontSize: "3em",
borderWidth: "10px"
}, 1500 );
$("#go").mouseleave(function(){
$("#block").animate({
width: "70%",
opacity: 0.4,
marginLeft: "0.6in",
fontSize: "3em",
borderWidth: "10px"
}, 1500 );
});
This does not seem to work and if I leave out the "mouseleave" part then it animates but stays at the animated state. I want it to revert back upon mouseleave.
Any help is appreciated.
Sincerely
Using stop() may help;
$("#go").hover(
function () {
$("#block").stop(true, true).animate(... your code here ...);
},
function () {
$("#block").stop(true, true).animate(... your code here ...);
}
);
JQuery stop(): http://api.jquery.com/stop/
JQuery hover(): http://api.jquery.com/hover/

Categories

Resources