Pinch-to-zoom og rotation
Kombinér PinchGestureHandler og RotationGestureHandler med samtidig genkendelse af bevægelser for at implementere en billedkomponent, der kan zoomes og roteres.
Pinch-to-zoom og rotation er en gratis React Native Academy-lektion på CoddyKit. Dette er lektion 4 af 4. Du kan læse alle 3 lektioner i dette læringsspor gratis i deres fulde længde — derefter låser CoddyKit PRO alle lektioner op samt praktiske øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Den er en del af læringsforløbet i React Native Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. React Native Academy-kurset indeholder 4 lektioner i alt.
Hvorfor knibning og rotation er vigtige
Knib for at zoome og rotation er typiske interaktioner på mobilen og findes i billedvisere, kort- og dokumentapps. En god implementering kræver genkendelse af multi-touch-gestures, der kører på den indbyggede tråd, samt jævne transform-opdateringer i realtid via Reanimated shared values.
React Native Gesture Handler leverer genkenderne Gesture.Pinch() og Gesture.Rotation(). Kombineret med Reanimateds useAnimatedStyle og useSharedValue giver de ekstremt jævne interaktioner, som ikke kan skelnes fra indbyggede implementeringer.
Gesture.Pinch: Registrering af skalering
Gesture.Pinch() registrerer en knibe- eller spredegesture med to fingre. Den vigtigste værdi i hændelsesobjektet er event.scale, som starter ved 1.0, når gesturen begynder, og ændres proportionalt med afstanden mellem fingrene. En værdi på 2.0 betyder, at fingrene er dobbelt så langt fra hinanden som ved starten.
Du skal kombinere gesturens trinvise skalering med en gemt grundskalering for at akkumulere zoom over flere knibegestures — ellers nulstilles hver ny knibning til 1.0.
import { Gesture } from 'react-native-gesture-handler';
import { useSharedValue, withSpring } from 'react-native-reanimated';
const scale = useSharedValue(1);
const savedScale = useSharedValue(1);
const pinch = Gesture.Pinch()
.onUpdate((e) => {
scale.value = savedScale.value * e.scale;
})
.onEnd(() => {
savedScale.value = scale.value;
});Begrænsning af zoomområdet
Uden begrænsning kan brugere zoome ind til enorme størrelser eller zoome ud, indtil billedet forsvinder. Definér et minimums- og maksimumsniveau for zoom, og begræns skaleringsværdien i callbacken onUpdate ved hjælp af en hjælpe-worklet.
Clamp-funktionen kører på UI-tråden som en worklet, så gesturens reaktion forbliver hurtig. Vælg grænseværdier, der passer til dit indhold — billedvisere tillader typisk zoom fra 1x til 5x, mens kort kan tillade langt bredere områder.
const MIN_SCALE = 1;
const MAX_SCALE = 5;
function clamp(value, min, max) {
'worklet';
return Math.min(Math.max(value, min), max);
}
const pinch = Gesture.Pinch()
.onUpdate((e) => {
scale.value = clamp(savedScale.value * e.scale, MIN_SCALE, MAX_SCALE);
})
.onEnd(() => {
savedScale.value = scale.value;
// Snap back if over-zoomed out:
if (scale.value < MIN_SCALE) {
scale.value = withSpring(MIN_SCALE);
savedScale.value = MIN_SCALE;
}
});Gesture.Rotation: Følg vinklen
Gesture.Rotation() følger vinkelændringen i en vridningsgesture med to fingre. Værdien event.rotation er angivet i radianer — den vinkel, fingrene har drejet fra gesturens startposition. En hel rotation med uret er cirka 6,28 radianer (2π).
Ligesom med skalering skal du akkumulere rotation over flere gestures ved at gemme den aktuelle rotation, når gesturen afsluttes, og føje den nye gesture-rotation til den gemte forskydning i efterfølgende gestures.
const rotation = useSharedValue(0);
const savedRotation = useSharedValue(0);
const rotationGesture = Gesture.Rotation()
.onUpdate((e) => {
rotation.value = savedRotation.value + e.rotation;
})
.onEnd(() => {
savedRotation.value = rotation.value;
});Anvendelse af skalering og rotation i useAnimatedStyle
Arrayet transform i useAnimatedStyle anvender både skalering og rotation. Rækkefølgen af transformationerne er vigtig: Anvend først skalering og derefter rotation (eller omvendt, afhængigt af den ønskede virkemåde). React Natives transform-array accepterer både numeriske skaleringsværdier og rotationsværdier i radianer direkte fra shared values.
Transformationen rotate kræver en streng med suffikset 'rad', mens scale tager et tal direkte. Brug strengsammenkædning (ikke template literals med backticks) til at konstruere rotationsstrengen i en worklet.
const animatedStyle = useAnimatedStyle(() => ({
transform: [
{ scale: scale.value },
{ rotate: rotation.value + 'rad' }, // concatenate string, no backticks
],
}));
return (
<GestureDetector gesture={composedGesture}>
<Animated.Image
source={{ uri: imageUrl }}
style={[styles.image, animatedStyle]}
/>
</GestureDetector>
);Sammensætning af knibning og rotation samtidig
En billedviser skal kunne knibe og rotere samtidig. Pak begge gestures ind i Gesture.Simultaneous, og send den sammensatte gesture til én enkelt GestureDetector. Så kan brugeren zoome og rotere med en to-finger-gesture i én flydende bevægelse.
Hvis du også tilføjer panorering samtidig, får du den komplette oplevelse fra en billedviser: Du kan zoome, rotere og flytte billedet med to fingre på én gang.
const composedGesture = Gesture.Simultaneous(
pinch,
rotationGesture,
pan
);
return (
<GestureDetector gesture={composedGesture}>
<Animated.Image
source={{ uri: imageUrl }}
style={[styles.image, animatedStyle]}
resizeMode='contain'
/>
</GestureDetector>
);Dobbelttryk for at nulstille zoom
En standardfunktion i billedvisere er at dobbelttrykke for at skifte mellem den naturlige størrelse og en indzoomet visning og derefter dobbelttrykke igen for at nulstille. Brug Gesture.Tap().numberOfTaps(2) til genkenderen for dobbelttryk, og animér skalering og rotation tilbage til deres startværdier med en spring-animation i dens handler.
Brug Gesture.Exclusive, og giv dobbelttryksgesturen prioritet over enkelttryk, for at forhindre, at enkelttrykket udløses under en dobbelttrykssekvens.
const doubleTap = Gesture.Tap()
.numberOfTaps(2)
.onEnd(() => {
if (scale.value > 1) {
// Reset to natural size:
scale.value = withSpring(1);
savedScale.value = 1;
rotation.value = withSpring(0);
savedRotation.value = 0;
offsetX.value = withSpring(0);
offsetY.value = withSpring(0);
} else {
// Zoom to 2x:
scale.value = withSpring(2);
savedScale.value = 2;
}
});Drejepunkt for knibezoom
Som standard skalerer skaleringstransformationen billedet fra dets midtpunkt. For en mere naturlig oplevelse bør billedet zoome omkring fokuspunktet — midtpunktet mellem de to fingre. Gesture-hændelsen indeholder event.focalX og event.focalY til dette formål.
Zoom omkring fokuspunktet kræver, at du justerer forskydningen sammen med skaleringen, så punktet under fingrene forbliver fast under zoom. Denne matematik indebærer beregning af den ændring i forskydningen, som skalafændringen medfører ved et bestemt fokuspunkt.
const pinch = Gesture.Pinch()
.onUpdate((e) => {
const newScale = clamp(savedScale.value * e.scale, MIN_SCALE, MAX_SCALE);
const scaleDelta = newScale / scale.value;
// Adjust offset to keep focal point fixed:
offsetX.value = e.focalX - scaleDelta * (e.focalX - offsetX.value);
offsetY.value = e.focalY - scaleDelta * (e.focalY - offsetY.value);
scale.value = newScale;
});Grænsebegrænsninger efter panorering og zoom
Efter indzoomning kan brugeren panorere for at se forskellige dele af billedet. Du bør dog begrænse panoreringen, så billedet ikke kan trækkes, så et tomt lærred uden for kanterne bliver synligt. Beregn den maksimale panoreringsforskydning ud fra den aktuelle skalering og billedets dimensioner, og begræns forskydningen i panoreringens onUpdate.
Det er denne finpudsning, der adskiller en professionel billedviser fra en grov prototype. Begrænsningslogikken består af nogle få linjer matematik, der kører som worklets på UI-tråden.
const IMAGE_WIDTH = 300;
const CONTAINER_WIDTH = 375;
const pan = Gesture.Pan()
.onUpdate((e) => {
const maxOffsetX = Math.max(0, (scale.value * IMAGE_WIDTH - CONTAINER_WIDTH) / 2);
offsetX.value = clamp(
savedOffsetX.value + e.translationX,
-maxOffsetX,
maxOffsetX
);
});Animering tilbage efter for kraftig zoom
Når brugeren løfter fingrene efter at have zoomet for langt (under minimum eller over maksimum), skal du med en spring-animation føre skaleringen tilbage til grænsen i stedet for at lade billedet blive vist i en usædvanlig størrelse. Gør dette i callbacken onEnd for knibegesturen.
På samme måde skal du nulstille panoreringsforskydningen til nul, når brugeren zoomer ud igen til 1x, så billedet vender tilbage til midten. Denne kombination af grænsekontroller i onEnd får komponenten til at føles gennemarbejdet og forudsigelig.
const pinch = Gesture.Pinch()
.onEnd(() => {
if (scale.value < MIN_SCALE) {
scale.value = withSpring(MIN_SCALE);
savedScale.value = MIN_SCALE;
// Reset pan to center:
offsetX.value = withSpring(0);
offsetY.value = withSpring(0);
} else if (scale.value > MAX_SCALE) {
scale.value = withSpring(MAX_SCALE);
savedScale.value = MAX_SCALE;
} else {
savedScale.value = scale.value;
}
});Sæt det hele sammen
En komplet billedviser, der kan zoome, rotere og panorere, kombinerer: shared values til skalering, rotation og forskydning; useAnimatedStyle, der anvender alle transformationerne; Gesture.Simultaneous, der sammensætter knibning, rotation, panorering og dobbelttryk; samt begrænsning ved grænser i onUpdate og korrektion med spring-animation i onEnd.
Det er en af de mest imponerende interaktioner, du kan bygge i React Native, og den kører udelukkende på UI-tråden uden involvering af JavaScript-tråden under gesturen — så den ikke kan skelnes fra en indbygget implementering.
const composed = Gesture.Simultaneous(
Gesture.Exclusive(
doubleTap,
singleTap
),
pan,
pinch,
rotationGesture
);
const style = useAnimatedStyle(() => ({
transform: [
{ translateX: offsetX.value },
{ translateY: offsetY.value },
{ scale: scale.value },
{ rotate: rotation.value + 'rad' },
],
}));Hurtig kontrol
Afprøv din forståelse af begreberne inden for React Native Mobile Development fra denne lektion.
Opsummering af lektionen
I denne lektion har du lært, at Gesture.Pinch() leverer event.scale til at følge zoom med to fingre i forhold til gesturens start, at Gesture.Rotation() leverer event.rotation i radianer til at følge vridning med to fingre, og at Gesture.Simultaneous sammensætter knibning, rotation og panorering, så alle tre fungerer samtidig og giver en komplet billedviseroplevelse. Nu konfigurerer vi brugerdefinerede URL-skemaer til deep linking til bestemte appskærme.
Lær JavaScript med en AI-underviser — gratis
Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.
- Kurser
- 30
- Lektioner
- 120
Ofte stillede spørgsmål
Er lektionen “Pinch-to-zoom og rotation” gratis?
Ja — alle 3 lektioner i læringssporet React Native Academy, inklusive “Pinch-to-zoom og rotation”, kan læses gratis i deres fulde længde her på webstedet. Derefter låser CoddyKit PRO alle lektioner op samt interaktive øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. React Native Academy-kurset indeholder 4 lektioner i alt.
Hvad lærer jeg i “Pinch-to-zoom og rotation”?
Kombinér PinchGestureHandler og RotationGestureHandler med samtidig genkendelse af bevægelser for at implementere en billedkomponent, der kan zoomes og roteres. Du øver dig i React Native Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.
Skal jeg have erfaring for at begynde på React Native Academy?
Der kræves ingen tidligere erfaring. React Native Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 4 af 4.
Hvor lang tid tager lektionen “Pinch-to-zoom og rotation”?
De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.
Kan jeg skrive og køre kode i denne React Native Academy-lektion?
Ja. Alle React Native Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.
Alle lektioner i dette kursus
- Installation af Reanimated og shared values
- Worklets og kørsel af kode på UI-tråden
- Pan- og swipe-bevægelser med Gesture Handler
- Pinch-to-zoom og rotation