Framer Motion not updating zIndex with keyframes - framer-motion

I am trying to animate a stack of cards where the active one slides out and comes on top of the other cards. To get the full effect, I need the z-index to change in the middle of the animation. It looks like the whole animation, including the end result shows that the property for the z-index is included in the animation, but the value never changes at any point.
Here is my code:
const variants = {
top: { x: ['calc(0% + 0px)', 'calc(-100% - 10px)', 'calc(0% - 0px)'], zIndex: [0, 5, 5] },
default: { x: 'calc(0% + ' + 5 * index + 'px)', y: 5 * index, zIndex: 1 },
}
return (
<AnimatePresence>
<motion.div
key={key}
variants={variants}
animate={isActive ? 'top' : 'default'}
transition={{ type: 'ease', duration: 1.5 }}
style={{
gridColumn: 1,
gridRow: 1,
position: 'relative',
}}
>
{children}
</motion.div>
</AnimatePresence>
)

Related

Framer Motion Wait to Calculate value before Starting animation

I define x and y values to hide from as state:
const [x, setX] = useState(0);
const [y, setY] = useState(0);
I have the following variant defined:
const transition = {
delay: 0,
duration: 0.5
};
const fromXYVariant = {
visible: {
y: 0,
x: 0,
transition
},
hidden: {
x,
y,
transition
}
};
and use it as
<AnimatePresence>
{!context.isGrouped(towerId2) ? (
<motion.div initial="hidden" animate="visible" exit="hidden" variants={fromXYVariant}>
<div>...</div>
</motion.div>
) : null}
</AnimatePresence>
I set my state variables using some complicated logic. However, I am running into an issue where, on the first "hidden animation" I use x and y as 0, because I haven't calculated them yet for my state.
My solution would be pausing the animation for a half a second or so while I do the math and then animate with the new values.
My question is, how do I pause framer motion from doing the animation while I do the math for the x and y not to be 0?
To pause framer motion from doing the animation you must use delay but instead of 0 as you are doing, you use 0.5 as you wished.
As you can see here:
With delay, you add a pause before the start of the animation (also in seconds). It will only delay the beginning of the initial animation; and not insert pauses between the repetitions.
And also seen in the framer motion documentation:
Delay the animation by this duration (in seconds). Defaults to 0.
const transition = {
delay: 0.2
}
There is also delayChildren:
When using variants, children animations will start after this duration (in seconds). You can add the transition property to both the Frame and the variant directly. Adding it to the variant generally offers more flexibility, as it allows you to customize the delay per visual state.
const container = {
hidden: { opacity: 0 },
show: {
opacity: 1,
transition: {
delayChildren: 0.5
}
}
}
const item = {
hidden: { opacity: 0 },
show: { opacity: 1 }
}
return (
<motion.ul
variants={container}
initial="hidden"
animate="show"
>
<motion.li variants={item} />
<motion.li variants={item} />
</motion.ul>
)

Framer Motion Does not Loop

I'm trying to loop an animation with the Framer Motion library after a small delay. The animation itself will play when it's mounted, on the webpage refresh, however does not repeat. Iv'e looked through the docs and this seems to be similar syntax.
const AnimateTrial = {
initial: {
opacity: 0,
x: -100,
y: -35,
scale: 0.9,
},
animate: (i) => {
const delay = 5 + i * 0.5;
return {
opacity: 1,
x: -10,
y: -35,
transition: {
opacity: { delay, duration: 1.5 },
x: { delay, duration: 1.5},
repeatType: "Infinity",
repeatDelay: 5,
},
};
}
I have also tried passing:
transition={{ repeat: Infinity, repeatDelay: 5 }}
But am yet to have it work. Any ideas!
I can confirm the remainder of the animation works, but it does not loop.
Having never laid eyes upon a transition object nested inside an animate function, I had to take this to code sandbox.
I'm new to Framer Motion myself but there are multiple things that strike me as odd and how I would fix them:
Setting a duration on several properties within transition. I don't believe this is a supported feature, so I'm moving it for this answer as both your opacity and x properties share the same duration.
transition: {
duration: 1.5,
opacity: delay,
x: delay,
repeatType: "Infinity",
repeatDelay: 5
}
Setting a repeatType without a repeat will not loop the animation. Setting repeat: Infinite will (and you can drop the repeatType).
transition: {
duration: 1.5,
opacity: delay,
x: delay,
repeat: Infinity,
repeatDelay: 5
}
Note that we still do not have a repeating animation.
Using animate as a function. I'm not sure, but I think the entire function might only get evaluated once and immediately discarded. I believe that the second time Framer Motion looks at the delay value it fails, thus not animating that specific property. (I am also not sure what you are trying to achieve with using delay inside the x and opacity properties.)
If we change either the opacity or x to use 0 as a value rather than delay, you can see that it will behave as expected - whereas the unchanged property only animates once. Changing them both will display the looping behavior you are looking for:
transition: {
duration: 1.5,
opacity: 0,
x: 0,
repeat: Infinity,
repeatDelay: 5
}
Thus, we've reached our final code:
const AnimateTrial = {
initial: {
opacity: 0,
x: -100,
y: -35,
scale: 0.9
},
animate: (i) => {
const delay = 5 + i * 0.5; // (now unused)
return {
opacity: 1,
x: -10,
y: -35,
transition: {
duration: 1.5,
opacity: 0,
x: 0,
repeat: Infinity,
repeatDelay: 5
}
};
}
};
Here's a live demo showcasing the working animation loop. (I changed repeatDelay to 1 for testing speed purposes).

Flatlist changes position of renderItem as scroll to more data in horizontal view

i have map view on top map view i am rendering Flatlist of cards with horizontal scroll which contains 500+ data.
the card is in the bottom is in the center and shows some part of Next and Previous Card but after Scrolling 20 to 30 it start shifting towards the Left side as further, it goes cards are totally misplaced
<Animated.FlatList
ref={scrollView}
horizontal
pagingEnabled
decelerationRate={0}
getItemLayout={(data, index) => ({
length: CARD_WIDTH,
offset: (CARD_WIDTH + 20) * index,
index,
})}
scrollEventThrottle={1}
onScrollToIndexFailed={() => {}}
showsHorizontalScrollIndicator={false}
snapToInterval={CARD_WIDTH + 20}//CARD_WIDTH = 310 AND 20 IS MARGIN
snapToAlignment="center"
style={styles.scrollView}
contentInset={{
top: 0,
left: SPACING_FOR_CARD_INSET,//SPACING_FOR_CARD_INSET=width - (CARD_WIDTH+20)/2
bottom: 0,
right: SPACING_FOR_CARD_INSET,
}}
contentContainerStyle={{
paddingHorizontal:
Platform.OS === 'android' ? SPACING_FOR_CARD_INSET : 0,
}}
onScroll={Animated.event(
[
{
nativeEvent: {
contentOffset: {
x: mapAnimation,
},
},
},
],
{useNativeDriver: true},
)}
data={stationData}
renderItem={renderPromotionItem}
scrollsToTop={false}
keyExtractor={item => item.id}
/>

Change Bottom Left Vertical Radius React Native

I am trying to make a background using two View to look , but I am falling to set the "start" of the radius on the left size.
The result I get using :
borderBottomLeftRadius: '20%',
borderBottomRightRadius: '40%',
Is this:
But I want this:
I want the "radius" start more vertically
Any tips how I get this effect?
Thank you
Exact shaping like this through radius is probably not possible, I achieved this by use of transform: [{ scale }]
Here is the code
const { width } = useWindowDimensions();
<View
style={{
backgroundColor: '#00ffff',
borderBottomLeftRadius: width / 3,
borderBottomRightRadius: width / 2,
borderWidth: 2,
borderColor: 'black',
height: width / 2,
width: width,
transform: [{ scale: 1.4 }],
}}
/>
Here what it looks like, is this workable for you?
you can tweak the values a little bit to meet your requirement.

The top half of larger label sizes get cut off in react-native-simple-radio-button

I am using the react-native-simple-radio-button package. If I specify a fontSize for the label greater than 22, the top half gets cut off. Making the radio buttons even bigger does not seem to make a difference.
Here is my code:
let radio_props = [
{label: 'ABC ', value: 0},
{label: 'DEF', value: 1}
]
let menu = <View style={{marginLeft: 40, marginTop: 40}}>
<RadioForm
radio_props = {radio_props}
buttonSize = {40}
buttonOuterSize={60}
labelStyle = {{fontSize: 30}}
initial={this.state.mode}
formHorizontal={true}
onPress={(value) => this.onPress(value)}
/>
</View>
This code produces the following results:
Is there something I am doing wrong or is it a bug in the react-native-simple-radio-button module?
Adding padding to the top worked for me
labelStyle={{
fontSize: 30,
paddingTop: 6
}}

Resources