Animate scale react - javascript

I am trying to animate the scale of my react component. It seems fairly simple and this was basically right out of the React-Motion examples:
var component = () => {
let style = { scale: spring(1.1, presets.wobbly)};
return (
<Motion style={style}>
{value =>
<div
style={{
backgroundColor: 'purple',
height: '50%', width: '50%',
transform: `scale(${value.scale})`,
WebkitTransform: `scale(${value.scale})`,
}}>
</div>
}
</Motion>
);
}
but the component keeps disappearing or not displaying properly for a variety of reasons. How do I get this component's scale to animate properly?

You don't want to use value.scale but just value. Also to improve readability you can use scale instead of value as your parameter. Check this article for a simple example
var component = () => {
let defaultStyle = {scale: 0};
let style = { scale: spring(1.1, presets.wobbly)};
return (
<Motion defaultStyle={defaultStyle} style={style}>
{({scale}) =>
<div
style={{
backgroundColor: 'purple',
height: '50px', width: '50px',
transform: `scale(${scale})`,
WebkitTransform: `scale(${scale})`,
}}>
</div>
}
</Motion>
);
}

Related

why react native tab view is taking white space when sliding to next tab

In react native tab view when I scroll to the bottom and slide to the next page when I am getting black space. Is there any way I can re-render the slide from top:
const renderTabs = () => {
return (
<>
<TabView
onIndexChange={index => setIndex(index)}
navigationState={{index: tabIndex, routes}}
renderScene={renderScene}
renderTabBar={renderTabBar}
initialLayout={{
height: 0,
width: Dimensions.get('window').width,
}}
// lazy
/>
</>
);
};
const renderTabBar = props => {
const y = scrollY.interpolate({
inputRange: [0, HeaderHeight],
outputRange: [HeaderHeight, 0],
extrapolateRight: 'clamp',
});
return (
<Animated.View
style={{
top: 0,
zIndex: 1,
position: 'absolute',
transform: [{translateY: y}],
width: '100%',
}}>
<TabBar
{...props}
onTabPress={({route, preventDefault}) => {
if (isListGliding.current) {
preventDefault();
}
}}
style={styles.tab}
renderLabel={renderLabel}
scrollEnabled={true}
indicatorStyle={styles.indicator}
/>
</Animated.View>
);
};
The next slide should not be taking white space - when I touch to screen and try to slide up then only it will become responsive

how to animate menu items from single point react native

I am trying to make an animated menu components which consists out of a main menu button and a few menu items. I am trying to make the menu items to be animated in the following way (see gif below):
See below what i have tried so far but i am unsure of how to accomplish the desired effect. Since i dont know how many menu items there will be and thus cannot set predefined sizes for the container.
In my current attempt i do use predefined sizes and also have no control over each specific item's bounce and delay.
I am new to react native and definitely completely lost when it comes to animating layouts. Any help or pointers would be greatly appreciated!
(this is a part of a more exhaustive menu component hence the additional parent views, but i left most of that out to keep the question to the point).
menu component:
const Menu = function (props: any) {
const anim_def = { duration: 500, easing: Easing.out(Easing.exp) }
const animated_height = useSharedValue(60);
const animated_menu = useAnimatedStyle(() => {
return {
position: "absolute",
bottom: 20,
left: 20,
display: "flex",
flexDirection: "column",
overflow: "hidden",
height: withTiming(animated_height.value, anim_def),
}
});
const generate_menuitems = (): ReactNode[] | null => {
const items: ReactNode[] = [];
if (props.menu_items === undefined) return null;
props.menu_items.forEach((item, index) => {
const styles: ViewStyle = {
marginTop: (index === 0) ? 0 : 20,
backgroundColor: item.backgroundColor
}
items.push(<ImageButton
image={item.image ?? 0}
onPress={() => { on_press_behaviour(index, item); }}
underlayColor={item.highlightColor}
style={[style.buttons, props.style?.buttons, styles]}
></ImageButton>)
});
return items;
}
const on_open_menu = () => {
animated_height.value = 300;
}
return (
<View pointerEvents="box-none" style={{ ...style.container, ...props.style?.container }}>
<View pointerEvents="box-none" style={style.container_wrapper}>
<Animated.View style={animated_menu}>
<ImageButton onPress={on_open_menu} onLayout={(l: LayoutChangeEvent) => {console.log(l.nativeEvent.layout)}} image={0} underlayColor="orange" style={[style.buttons, props.style?.buttons, { position: "absolute", left: 0, bottom: 0, zIndex: 2 }]}></ImageButton>
{generate_menuitems()}
</Animated.View>
</View>
</View>
);
}
component styles:
const style = StyleSheet.create({
container: {
position: "absolute",
left: 0,
bottom: 0,
width: "100%",
height: "100%",
},
container_wrapper: {
position: "relative",
width: "100%",
height: "100%",
},
buttons: {
width: 60,
aspectRatio: 1,
borderRadius: 30,
backgroundColor: "green",
marginTop: 20
}
});

React native animated object does not move

I am new to React Native animated, and I am trying to incorporate it into my app. I currently have an object that appears to fall from the middle to the bottom of the screen, using frequent state updates like this:
const [objHeight, setObjHeight] = useState((Dimensions.get("screen").height)/2)
useEffect(()=>{
if(objHeight > 0){
timerId = setInterval(()=>{
setObjHeight(objHeight => objHeight - 3)
}, 30) //30ms
return ()=>{
clearInterval(timerId)
}
},[objHeight])
//then the object looks like:
<View
style = {[{
position: "absolute",
backgroundColor: 'blue',
width: 50,
height: 60,
bottom: objHeight,
}]}>
</View>
I understand that this is an inefficient way to do animations on react, and that by using react animated we can make animate this on the UI thread instead. I have tried to replicate the above using react native animated.
const objHeight = new Animated.Value(screenHeight/2)
Animated.loop(
Animated.timing(objHeight, {
toValue: objHeight>0 ? objHeight - gravity : null,
duration: 3000,
useNativeDriver: true
}),
{iterations: 1000}
).start()
<Animated.View
style = {[{
backgroundColor: 'blue',
width: 50,
height: 60,
bottom: 200,
transform:[{translateY: objHeight}]
}]}>
</Animated.View>
However, the object does not move/animate. It just stays at the same height. What am I doing wrong? I find the documentation on react native animated is not particularly helpful.
Thank you
Snack Link
First create an Animated.Value with some initial value:
const bottomAnim = useRef(new Animated.Value(Dimensions.get('screen').height / 2)).current;
Then on component mount start the animation:
useEffect(() => {
Animated.timing(bottomAnim, {
toValue: 0,
duration: 3000,
useNativeDriver: true,
}).start();
}, []);
Finally, bind the animated value to the component:
return (
<Animated.View
style={[
{
position: 'absolute',
backgroundColor: 'blue',
width: 50,
height: 60,
bottom: bottomAnim,
},
]}/>
);

react native deck swiper library

enter image description here
I'm trying to change the layout of the images which are showing below I want to show them on the top I just want to change the layout of the images which are showing below I want to show them above the first card
export default function App({navigation}) {
const [index, setIndex] = React.useState(0);
const onSwiped = () => {
transitionRef.current.animateNextTransition();
setIndex((index + 1) % data.length);
};
return (
<SafeAreaView style={styles.container}>
<View
style={{
backgroundColor: 'black',
opacity: 0.05,
transform: [{rotate: '45deg'}, {scale: 1.6}],
position: 'absolute',
left: -15,
top: 30,
}}></View>
<View style={styles.swiperContainer}>
<Swiper
ref={swiperRef}
cards={data}
cardIndex={index}
renderCard={card => <Card card={card} />}
infinite
backgroundColor={'transparent'}
onSwiped={onSwiped}
onTapCard={() => swiperRef.current.swipeLeft()}
cardVerticalMargin={50}
stackSize={stackSize}
animateCardOpacity={true}
stackScale={8}
stackSize={3}
verticalSwipe={false}
stackSeparation={13}
animateOverlayLabelsOpacity
animateCardOpacity
disableTopSwipe
disableBottomSwipe
/>
</View>
</SafeAreaView>
);
}
Change this in your styles: top: 30 => top: -30
Use stackseparation. stackSeparation={-20}

How to show multiple components in a specific position inside of a parent component in react-native?

I am trying to render multiple components inside of a parent component on a specific position (based on some calculations). The calculations that give me the vertical position look correct, but the components are not displayed in the position they should. I have tried both absolute window position and relative component position with no luck.
The parent looks like follows:
const top = 170;
const bottom = 10;
const left = 10;
const right = 10;
const styles = StyleSheet.create({
grid: {
flex: 1,
position: 'absolute',
top: top,
height: Dimensions.get('window').height - top - bottom,
width: Dimensions.get('window').width - left - right,
borderLeftColor: 'black',
borderLeftWidth: 1,
borderBottomColor: 'black',
borderBottomWidth: 1
}
});
const DrawGrid: React.FC<IDrawGrid> = ({ maxDistance, elements }) => {
const [gridSize, setGridSize] = useState<LayoutRectangle>();
return (
<View style={styles.grid} onLayout={(event) => {
setGridSize(event.nativeEvent.layout);
}}>
{elements.map((element, index) => {
return (
<DrawElement element={element} maxDistance={maxDistance} gridSize={gridSize} index={index * 2} />
)
})}
</View>
);
};
And the child component that renders all the elements looks like follows:
const top = 170;
const bottom = 20;
const left = 10;
const right = 10;
const styles = StyleSheet.create({
elementContainer: {
borderLeftColor: 'red',
borderLeftWidth: 1,
borderTopColor: 'red',
borderTopWidth: 1,
borderRightColor: 'red',
borderRightWidth: 1,
borderBottomColor: 'red',
borderBottomWidth: 1,
borderRadius: 5,
padding: 2,
position: 'relative',
alignSelf: 'flex-start'
}
});
const getVerticalPosition = (someDistance: number, maxDistance: number, height: number) => {
if (!someDistance || !maxDistance) return { top: 0 };
const topDistance = (1 - (someDistance / maxDistance)) * height;
return { top: topDistance };
};
const DrawElement: React.FC<IDrawElement> = ({ maxDistance, element, gridSize, index }) => {
const styleVertical = getVerticalPosition(someDistance, maxDistance, gridSize.height);
return (
<View key={key} style={[styles.elementContainer, styleVertical]}>
<Text>top: {styleVertical.top.toFixed(2)}</Text>
</View>
);
};
I can see how getVerticalPosition returns the right value, but the element is never located in the position expected. In the snapshot below I am printing the top value for each element, and we can see it is not respected at all. (horizontal location is out of the scope of the problem)
My first thought was that I am messing up the styles somehow, I also tried giving a different zindex to each element without luck. Any ideas what could happen? Any help would be much appreciated, thank you!
I think you don't understand how the layout type works in React Native. Here is a link: https://reactnative.dev/docs/flexbox#absolute--relative-layout. The main problem is relative position for each child element related to its own initial position.
By default, all elements in React Native have position equal to relative, so you don't need to put it in style definition.
To better understanding relative position scheme, I suggest you consider its rendering process in two steps:
rendering children without any of top, left, bottom, right properties;
shifting children according to their top, left, bottom, right properties from their current positions;
Imagine that you have such code:
<View style={styles.parent}>
<View style={styles.firstChild}/>
<View style={styles.secondChild}/>
</View>
const styles = StyleSheet.create({
parent: {
top: 100,
flex: 1,
},
firstChild: {
top: 100,
height: 50,
},
secondChild: {
top: 80,
height: 70,
},
});
If we apply two steps mentioned above to this example it will look like this:
   
To solve your problem you need to apply absolute position scheme to children. Only absolute position scheme place element, with for example top: 100 property, to 100 points down related to the current top of its parent.
I hope it will help you a little.

Categories