feat: synchronize searchbar animation with keyboard movement

This commit is contained in:
Adrian Castro
2024-02-18 21:06:29 +01:00
parent fe488b5e8b
commit 62fdd3e99c

View File

@@ -1,12 +1,11 @@
import React, { useEffect, useRef, useState } from "react"; import React, { useEffect, useState } from "react";
import { import { Keyboard, ScrollView, View } from "react-native";
Animated, import Animated, {
Dimensions, Easing,
Keyboard, useAnimatedStyle,
Platform, useSharedValue,
ScrollView, withTiming,
View, } from "react-native-reanimated";
} from "react-native";
import { getMediaPoster, searchTitle } from "@movie-web/tmdb"; import { getMediaPoster, searchTitle } from "@movie-web/tmdb";
@@ -18,8 +17,8 @@ import Searchbar from "./Searchbar";
export default function SearchScreen() { export default function SearchScreen() {
const [searchResults, setSearchResults] = useState<ItemData[]>([]); const [searchResults, setSearchResults] = useState<ItemData[]>([]);
const fadeAnim = useRef(new Animated.Value(1)).current; const translateY = useSharedValue(0);
const translateYAnim = useRef(new Animated.Value(0)).current; const fadeAnim = useSharedValue(1);
const handleSearchChange = async (query: string) => { const handleSearchChange = async (query: string) => {
if (query.length > 0) { if (query.length > 0) {
@@ -31,67 +30,52 @@ export default function SearchScreen() {
}; };
useEffect(() => { useEffect(() => {
const keyboardDidShowListener = Keyboard.addListener( const keyboardWillShowListener = Keyboard.addListener(
"keyboardDidShow", "keyboardWillShow",
(e) => { (e) => {
const screenHeight = Dimensions.get("window").height; translateY.value = withTiming(
const endY = e.endCoordinates.screenY; -(e.endCoordinates.height - 110), // determines the height of the Searchbar above keyboard, use Platform.select to adjust value if needed
const translateY = screenHeight - endY; {
duration: e.duration ?? 250, // duration always returns 0 on Android, adjust value if needed
Animated.parallel([ easing: Easing.out(Easing.ease),
Animated.timing(fadeAnim, { },
toValue: 1, );
duration: 200,
useNativeDriver: true,
}),
Animated.timing(translateYAnim, {
toValue:
-translateY +
Platform.select({ ios: 100, android: 300, default: 0 }),
duration: 200,
useNativeDriver: true,
}),
]).start();
}, },
); );
const keyboardDidHideListener = Keyboard.addListener(
"keyboardDidHide", const keyboardWillHideListener = Keyboard.addListener(
"keyboardWillHide",
() => { () => {
Animated.parallel([ translateY.value = withTiming(0, {
Animated.timing(fadeAnim, { duration: 250,
toValue: 1, easing: Easing.out(Easing.ease),
duration: 200, });
useNativeDriver: true,
}),
Animated.timing(translateYAnim, {
toValue: 0,
duration: 200,
useNativeDriver: true,
}),
]).start();
}, },
); );
return () => { return () => {
keyboardDidShowListener.remove(); keyboardWillShowListener.remove();
keyboardDidHideListener.remove(); keyboardWillHideListener.remove();
}; };
}, [fadeAnim, translateYAnim]); }, [translateY]);
const animatedStyle = useAnimatedStyle(() => {
return {
transform: [{ translateY: translateY.value }],
opacity: fadeAnim.value,
};
});
const handleScrollBegin = () => { const handleScrollBegin = () => {
Animated.timing(fadeAnim, { fadeAnim.value = withTiming(0, {
toValue: 0,
duration: 100, duration: 100,
useNativeDriver: true, });
}).start();
}; };
const handleScrollEnd = () => { const handleScrollEnd = () => {
Animated.timing(fadeAnim, { fadeAnim.value = withTiming(1, {
toValue: 1,
duration: 100, duration: 100,
useNativeDriver: true, });
}).start();
}; };
return ( return (
@@ -120,14 +104,10 @@ export default function SearchScreen() {
</ScreenLayout> </ScreenLayout>
</ScrollView> </ScrollView>
<Animated.View <Animated.View
style={{ style={[
position: "absolute", { position: "absolute", left: 0, right: 0, bottom: 0 },
left: 0, animatedStyle,
right: 0, ]}
bottom: 0,
transform: [{ translateY: translateYAnim }],
opacity: fadeAnim,
}}
> >
<Searchbar onSearchChange={handleSearchChange} /> <Searchbar onSearchChange={handleSearchChange} />
</Animated.View> </Animated.View>