Dynamic Animation translate limits on Slider - react-native

I have a task where I'm creating a 'slider' essentially, but it has two bars on the same slider. What I'm trying to do is move those sliders up and down the y axis but the bar you are sliding is not to move past it's twin. eg. Top Slider is not to move past the Bottom Slider and visa versa.
My thought is then that the output limits along the translateY will be dynamic.
So far, attempts have shown to have odd behaviours.
View Image Example
I have tried the top and bottom bars as pan responders with there movements on the y-axis, saved in a useState and that state is added to the outputRange on the translateY
`<Animated.Image
resizeMode="stretch"
source={Theme.defaultImages.progressBar}
style={{
width: hp(100) / 2.8,
height: hp(4),
position: 'absolute',
alignSelf: 'center',
transform: [
{
translateY: pan.y.interpolate({
inputRange: [0, height],
outputRange: [0, topBarYPositionState], //useState is added here for dynamic limit.
extrapolate: 'clamp',
}),
},
d],
}}
{...PanResponder.panHandlers}
/>`

Related

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>

Left-align a scaled View/Text with react-native's Animated API

I a trying to build a 'Material-UI-like' TextInput with a large label that shrinks down when the field is selected.
I am having issues with scaling the label. Applying a transform: [{scale: ...}] shrinks the Text, but does so around the center of the field. I am failing to keep the label left-aligned during the scaling process, as I'd need to dynamically be able to access the view's width to offset it, but I can't seem to be able to get it using normal means(i.e. onLayout, which does not seem to be triggered during the animation).
Here is an example demonstrating the issue:
import React from 'react';
import { View, Text, TextInput, Animated } from 'react-native';
export const F = (): JSX.Element => {
const scale = React.useRef(new Animated.Value(0.0)).current;
React.useEffect(() => {
const animation = Animated.timing(scale, {
toValue: 1.0,
duration: 1000,
useNativeDriver: true,
});
animation.start();
}, []);
return (
<View style={{ backgroundColor: 'red' }}>
<Animated.View
style={{
transform: [
{
scale: scale.interpolate({
inputRange: [0, 1],
outputRange: [1, 0.5],
}),
},
],
backgroundColor: 'yellow',
}}
onLayout={(e) => console.log({ view: e.nativeEvent.layout })}>
<Text onLayout={(e) => console.log({ text: e.nativeEvent.layout })}>
Label
</Text>
</Animated.View>
<TextInput style={{ backgroundColor: 'blue' }} />
</View>
);
};
Example after the text has been scaled by half:
Note how the yellow view (Text) is no longer left aligned because of the scaling.
I've created a stack to explain what I am trying to accomplish:
https://snack.expo.dev/#bertrand-caron/trembling-beef-jerky
I'd like the Label View (yellow) to stay left align when scaled, instead of being shrunk centered inside the red view.
I have two solution:
1. For this I have created a snack: https://snack.expo.dev/PFN07UigC .
Let me know if it fits. For left aligning I just used justify-content:'flex-start' to its container.
2. If you wish to calculate it you know the initial size with onLayout and you have the scale let us assume that scale you are using is 0.5 and the onLayout gave you 100 then the margin-left that you are wanted is (width-(width*scale))/2 which is in our case 25. But I don't see any need for that.
In my opinion, you should make the <Animated.Text/> rather than <Animated.View/>. But it will also work.
If you don’t use alignSelf: 'flex-start' it will take the same space as the Parent View.
Here is my solution: https://snack.expo.dev/#fanish/textinput-animation
<Animated.Text
style={{
...textStyle,
transform: [{ scale }],
alignSelf: 'flex-start',
}}>
Label
</Animated.Text>

React Native using Animated to hide Header (leaves blank space after TransformY)

I have implemented hiding header while scrolling in React native using Animated.
Here is the code:
const y = new Animated.Value(0);
const AnimatedWebView = Animated.createAnimatedComponent(WebView);
const HEADER_HEIGHT = 60;
const {diffClamp} = Animated;
function WebPage({route}) {
const diffClampY = diffClamp(y, 0, HEADER_HEIGHT);
const translateY = diffClampY.interpolate({
inputRange: [0, HEADER_HEIGHT],
outputRange: [0, -HEADER_HEIGHT],
});
return (
<SafeAreaView style={{flex: 1}}>
<Animated.View
style={{
height: HEADER_HEIGHT,
width: '100%',
position: 'absolute',
top: 0,
left: 0,
right: 0,
zIndex: 2,
backgroundColor: 'lightblue',
transform: [{translateY: translateY}],
}}
/>
<AnimatedWebView
source={{
uri: 'https://www.stackoverflow.com',
}}
originWhitelist={['*']}
containerStyle={{paddingTop: 60}}
bounces={false}
onScroll={Animated.event([{nativeEvent: {contentOffset: {y: y}}}])}
/>
</SafeAreaView>
);
}
Since Header is positioned absolute to stick to the top, I have given paddingTop(same as height of the header) to avoid header overlapping the contents of the WebView initially. Now because of this, when I scroll, as header disappears, it leaves blank space as shown:
Above is image before & after hiding the Header. Blank space is left where header is used to be. How should I dynamically change the padding so that as header disappears, there is no blank space left? I have tried without absolutely positioning the header and giving no paddingTop to the Webview, but still blank space.
Any help appreciated! Thanks
When you using translateY, it means you're moving your header away from its current position, not the place it holds. And the blank space you saw is kind of an anchor of the header (open your debugger, you will see your header component is just still in old position). In order to move your webview, just bind your webview's translateY along with your header, and you will have perfect animation.
<AnimatedWebView
source={{
uri: 'https://www.stackoverflow.com',
}}
originWhitelist={['*']}
containerStyle={{paddingTop: 60}}
bounces={false}
onScroll={Animated.event([{nativeEvent: {contentOffset: {y: y}}}])}
style={{
transform: [{translateY: translateY}]
}}
/>
Edit 1
I'm thinking of 3 solutions:
You will change the height of the webview along with its position. Check this out: Increase width height of view using animation.
Make your webview's height greater than its default height. So when you translate the webview, the redundant space will cover your blank space. In this case, you have to calculate the height of your webview using React Native Dimension
There is a transform's property, called scale. You can use it to stretch your webview, but I don't know if it will stretch your webview's content or not.

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

Animated header on scrollview

I have a scrollview on top of which i display a header. My goal is to animated so that when the user scrolls down, the header collapse and when the view scrolls up, the header expands.
I found plenty of exemple where the user has to scroll all the way up for the header to expand. What i'd like is for the header to expand as soon as the scroll view scrolls up.
How can I achieve this?
Here is what I have so far:
type State = { scrollY: Animated.Value };
....
headerHeight = this.state.scrollY.interpolate({
inputRange: [
0, 60
],
outputRange: [60, 0],
extrapolate: "clamp"
});
<Animated.View style={{ height: headerHeight, backgroundColor: "#F0f" }}
>
<ScreenHeader
ref={this.screenHeaderRef}
onTouchAvatar={this.handleOpenProfile}
onTouchNotifications={this.handleOpenNotification}
user={currentUser}
newNotifications={this.props.newNotifications}
/>
</Animated.View>
<WrappedComponent
onScroll={Animated.event([
{
nativeEvent: {
contentOffset: {
y:
this.state.scrollY
}
}
}
])}
onMomentumScrollEnd={this.handleMomentumScrollEnd}
{...this.props}
/>
So you are right about the animating the translateY property. So I did it a bit different way for sake of this question (Poorly, sorry about that, you need to play around a bit with this to get the right animation).
So try to set the style of the animated view's translateY to 0;
<Animated.View
style={[{
transform: [
{
translateY: this.transform
}
]
}, {
backgroundColor: 'red'
}]}
>
Then on scroll set it to -100 or whatever your header height.
later when the user comes back up, towards the top 0, you set it up to 0.
This will do the trick, hopefully.
Here's a small example, sorry for getting back late. :)
https://snack.expo.io/#subkundu/header-hideshow