Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 115 additions & 0 deletions src/features/PinchAnimation/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import React from 'react'
import { StyleSheet, View } from 'react-native'
import { SafeAreaView } from 'react-native-safe-area-context'
import { Header } from '../../components/Header'
import Animated, {
useSharedValue,
useAnimatedStyle,
withTiming,
// runOnJS,
} from 'react-native-reanimated'
import { Gesture, GestureDetector } from 'react-native-gesture-handler'

export const PinchAnimation = () => {
// Shared values for scale and pan
const scale = useSharedValue(1)
const savedScale = useSharedValue(1)

const translateX = useSharedValue(0)
const translateY = useSharedValue(0)
const savedTranslateX = useSharedValue(0)
const savedTranslateY = useSharedValue(0)

// --- Pinch gesture ---
const pinch = Gesture.Pinch()
.onBegin(() => {
savedScale.value = scale.value
})
.onUpdate(e => {
scale.value = savedScale.value * e.scale

// Calculate focal adjustment to keep the zoom centered on the focal point
const adjustedFocalX = e.focalX - 150
const adjustedFocalY = e.focalY - 150

translateX.value = savedTranslateX.value + adjustedFocalX * (1 - e.scale)
translateY.value = savedTranslateY.value + adjustedFocalY * (1 - e.scale)
})
.onEnd(() => {
// Clamp zoom out
if (scale.value < 1) {
scale.value = withTiming(1)
translateX.value = withTiming(0)
translateY.value = withTiming(0)
}
savedTranslateX.value = translateX.value
savedTranslateY.value = translateY.value
})

// --- Pan gesture ---
const pan = Gesture.Pan()
.onBegin(() => {
savedTranslateX.value = translateX.value
savedTranslateY.value = translateY.value
})
.onUpdate(e => {
translateX.value = savedTranslateX.value + e.translationX
translateY.value = savedTranslateY.value + e.translationY
})
.onEnd(() => {
savedTranslateX.value = translateX.value
savedTranslateY.value = translateY.value
})

// Combine pinch + pan
const gesture = Gesture.Simultaneous(pinch, pan)

// Animated style
const animatedStyle = useAnimatedStyle(() => ({
transform: [
{ translateX: translateX.value },
{ translateY: translateY.value },
{ scale: scale.value },
],
}))
return (
<SafeAreaView style={styles.root}>
<Header />
<View>
<GestureDetector gesture={gesture}>
<Animated.View style={[styles.canvas, animatedStyle]}>
<Animated.View style={styles.child} />
</Animated.View>
</GestureDetector>
</View>
</SafeAreaView>
)
}

const styles = StyleSheet.create({
root: {
flex: 1,
backgroundColor: '#FDCFFA',
},
container: {
flex: 1,
backgroundColor: '#111',
justifyContent: 'center',
alignItems: 'center',
},
canvas: {
width: 300,
height: 300,
backgroundColor: '#333',
borderRadius: 10,
overflow: 'hidden',
justifyContent: 'center',
alignItems: 'center',
},
child: {
width: 150,
height: 150,
backgroundColor: '#4caf50',
borderRadius: 10,
},
})
3 changes: 3 additions & 0 deletions src/navigation/NavigationStack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import AnimationsScreen from '../features/AnimationsScreen'
import BottomSheetScreen from '../features/BottomSheets/BottomSheetScreen'
import SwipeAnimation from '../features/SwipeAnimation'
import { FloatingButton } from '../features/FloatingButton'
import { PinchAnimation } from '../features/PinchAnimation'

const Stack = createNativeStackNavigator()
const Drawer = createDrawerNavigator()
Expand All @@ -27,6 +28,7 @@ const drawerItems = [
{ key: 'BottomSheets', label: 'Bottom Sheets', screen: 'BottomSheetsScreen' },
{ key: 'SwipeAnimation', label: 'Swipe Animation', screen: 'SwipeAnimation' },
{ key: 'FloatingButton', label: 'Floating Button', screen: 'FloatingButton' },
{ key: 'PinchAnimation', label: 'Pinch Animation', screen: 'PinchAnimation' },
]

const CustomDrawerContent = () => {
Expand Down Expand Up @@ -102,6 +104,7 @@ const HomeStackNavigator = () => (
<Stack.Screen name="BottomSheetsScreen" component={BottomSheetScreen} />
<Stack.Screen name="SwipeAnimation" component={SwipeAnimation} />
<Stack.Screen name="FloatingButton" component={FloatingButton} />
<Stack.Screen name="PinchAnimation" component={PinchAnimation} />
</Stack.Navigator>
)

Expand Down