TouchableOpacity is not working when Transform Animation is applied - react-native

Below code is to render a Touchable button with Transform Animation.
const { scrollY, headerScrollDistance } = this.state;
const profileImageTranslateX = scrollY.interpolate({
inputRange: [0, headerScrollDistance],
outputRange: [0, -(ScreenWidth /2) + 32],
extrapolate: 'clamp',
});
const profileImageTranslateY = scrollY.interpolate({
inputRange: [0, headerScrollDistance],
outputRange: [0, -11],
extrapolate: 'clamp',
});
const profileImageScale = scrollY.interpolate({
inputRange: [0, headerScrollDistance / 2, headerScrollDistance],
outputRange: [1, 0.8, 0.6],
extrapolate: 'clamp',
});
return (
<Animated.View
style={[
Styles.animatedView.profileStyle,
{
transform: [
{ translateX: profileImageTranslateX },
{ translateY: profileImageTranslateY },
{ scale: profileImageScale }
]
}
]}
>
<TouchableOpacity activeOpacity={0.5} onPress={() => this.props.history.push('./profilePhotoChanger')}>
<ImageComp profileImageUrl={profileimageurl} imageStyle={Styles.homePageImageStyle} />
</TouchableOpacity>
</Animated.View>
);
As page scrolls, Animation applies to Touchable button. Button is working as expected when transform animation is not applied. But not working when animation is applied. If page comes back to it's normal state(i.e scrolling back) then button works as expected.
Is it normal behaviour in react-native that TouchableOpacity's onPress wont't work when animation applied? or is something wrong with my code?

You can try one of the following option if it works for you
1- import { TouchableOpacity } from 'react-native-gesture-handler';
2- Change height of Animated.View which contain TouchableOpacity (to
fit size of TouchableOpacity)
3- By moving <Animated.View> inside TouchableOpacity
Look like there is open discussion on Touchableopacity not working inside Animated.View

Related

React-native: prevent Swipeable component swipe to outside the screen

I have a screen that show chat messages, and I make the item chat able to swipe to reply like FB Messenger. I'm using Swipeable component from react-native-gesture-handler. But I have a troble: whenever I swipe fastly, the item will swipe to outside the screen like this: https://i.stack.imgur.com/uIEWN.png
How can I fix it?
My code for Swipeable Item:
<Swipeable
failOffsetX={
!isMyMessage ? [0, SCREEN_WIDTH / 3] : [-SCREEN_WIDTH / 2, 0]
}
ref={swipeableRef}
friction={2}
enableTrackpadTwoFingerGesture
renderLeftActions={renderSwipeableActions }
renderRightActions={renderSwipeableActions }
onSwipeableClose={onSwipeableClose}
onSwipeableOpen={() => {}} />
And this one for render UI when swipe action activate :
const renderSwipeableActions = (
_progress: Animated.AnimatedInterpolation,
dragX: Animated.AnimatedInterpolation,
) => {
const transformLeft = dragX.interpolate({
inputRange: [0, 50, 100, 101],
outputRange: [-20, 0, 0, 1],
extrapolate: 'clamp',
});
const transformRight = dragX.interpolate({
inputRange: [0, 50, 100, 101],
outputRange: [1, 0, 0, -20],
extrapolate: 'clamp',
});
return (
<RectButton
style={{
flex: 1,
alignItems: !isMyMessage ? 'flex-start' : 'flex-end',
}}>
<Animated.View
style={[
{
transform: [
{translateX: !isMyMessage ? transformLeft : transformRight},
],
},
]}>

How to get image to take up whole screen on press using Transform with React Native

I'm creating a chat app and want to make a picture take up the whole screen when it is clicked on like in other chat apps. The code I have so far scales it to the whole screen and centers it horizontally, but only because I know where on the X axis it is starting at and then calculate the translateX from there. The problem is that, for the Y axis, an image can be anywhere on the screen when it is clicked so I can't do the same thing I did for translateX. How can I get the Y position of the image to calculate how much I need to translate it on the Y Axis.
I know there were similar solutions that use spring, but I like the look of the image expanding from where it begins rather than it coming up from the bottom.
Here is my current code:
<Animated.View
style={[
styles.fadingContainer,
{
transform: [
{
scale: Anim.interpolate({
inputRange: [0, 0.5, 1],
outputRange: [1, 1.5, 2],
}),
},
{
translateX: Anim.interpolate({
inputRange: [0, 0.5, 1],
outputRange: [
0,
Dimensions.get("window").width / 16,
Dimensions.get("window").width / 8,
],
}),
},
{
translateY: Anim.interpolate({
inputRange: [0, 0.5, 1],
outputRange: [
** What do I put here? **
],
}),
},
],
},
]}
>
<Text style={styles.fadingText}>Fading View!</Text>
</Animated.View>

interpolate cause `node cannot be cast to number`

An re-animation (1.13) is used to toggle accordion in React Native app. When accordion is open or close, an arrow is up or down. interpolate is used to animate when arrow from up to down or vise verse.
import Animated, { useValue, interpolate, Easing, useCode, State, greaterThan, lessThan } from "react-native-reanimated";
const animatedController = useValue(0); //<<==animated value between [0, 1]
const arrowAngle = interpolate(animatedController, { //<<==interpolate causes error of node cannot be cast to number
inputRange: [0, 0.5, 1],
outputRange: ['0rad', `${0.5*Math.PI}rad`,`${Math.PI}rad`],
extrapolate: Extrapolate.CLAMP,
});
return (
<>
<TouchableWithoutFeedback onPress={() => setOpen(!open)}>
<View style={styles.titleContainer}>
<Text>{title}</Text>
<Animated.View style={{ transform: [{ rotateZ: arrowAngle }] }}> //<<==arrowAngle call here
<Icon name="chevron-down-outline" size={20} />
</Animated.View>
</View>
</TouchableWithoutFeedback>
</>
)
However the method above causes the error of node cannot be cast to number as below. This interpolate seems very simple. What's wrong here?
The output range shall be a number like this:
const arrowAngle = interpolate(animatedController, {
inputRange: [0, 0.5, 1],
outputRange: [0.01, 1/2*Math.PI,Math.PI], //<<==shall be digital
extrapolate: Extrapolate.CLAMP,
});

Prevent negative animated value on scroll

I have header collapsed on scroll event. On ios scroll offset value can be negative and it cause problem.
Is there any way to prevent animated value being negative?
Here is my code
const ScrollYDiffClamp = Animated.diffClamp(positionY, 0, 60);
const headerTranslate = ScrollYDiffClamp.interpolate({
inputRange: [0, 1],
outputRange: [0, -1],
});
return (
<>
<Header style={{transform: [{translateY: headerTranslate}]}}/>
<Animated.ScrollView
onScroll={Animated.event([{nativeEvent: {contentOffset: {y: positionY}}}], {
useNativeDriver: true,
})}>
</Animated.ScrollView>
</>
)
I believe you can disable bounces on your Animated.ScrollView
bounces={false}
or you can add additional interpolate and fix this issue
const headerHeight = 50;
const clampedScrollY = scrollY.interpolate({
inputRange: [0, 1],
outputRange: [0, 1],
extrapolateLeft: 'clamp',
});
const diffClampScrollY = Animated.diffClamp(clampedScrollY, 0, headerHeight);
const translateY = diffClampScrollY.interpolate({
inputRange: [0, headerHeight],
outputRange: [0, -headerHeight],
extrapolate: 'clamp',
});
Try adding this to your interpolation configuration.
extrapolate: "clamp"
Oleskii's answer worked for me, the only issue I was having was on the bottom the issue that this solved on the top was still happening. Just adding more to the max height seems to have resolved the issue though. Something like:
const diffClampScrollY = Animated.diffClamp(clampedScrollY, 0, headerHeight + 300);
the bouncing that happens in the ScollView seems to be covered with 300 added to the max output of the diffClamp

React Native animate view position based on flat list offset

I want to animate a view's(say abcView) position based on main container flat list scroll offset. If the user scrolls down, abcView's position should move to bottom proportionately(vice versa when user scrolls back up). The position of abcView should change in proportion to the flatlist offset and not in one go. I want to use animated API but need ideas how to proceed with this.
You could try below functional component
function SomeComponent() {
const [scrollY] = useState(new Animated.Value(0));
const translateY = scrollY.interpolate({
inputRange: [0, 150],
outputRange: [0, 150],
extrapolate: 'clamp',
useNativeDriver: true,
});
return (
<View>
<Animated.FlatList
onScroll={Animated.event([{ nativeEvent: { contentOffset: { y: scrollY } } }])}
/>
<Animated.View
style={{
transform: [{ translateY: translateY }],
}}
></Animated.View>
</View>
)
}
Since you said you need ideas, I think what you are looking for is the parallax effect. You can either go ahead building your own or you can search for such libraries e.g. react-native-parallax-header