Pinch-to-Zoom — lényeg, a csípés gesztus feldolgozása mobilalkalmazásokban

Szerző: IT Sectr Megjelenés: 2026-02-27 Olvasási idő: 8 perc
Pinch-to-Zoom (ujjakkal csípés) — egy multitouch nagyítási gesztus, amely során a felhasználó két ujját összehúzza vagy széttárja a képernyőn a tartalom kicsinyítéséhez vagy nagyításához. Ez a gesztus de facto szabvánnyá vált képek, térképek, weboldalak és dokumentumok mobileszközökön történő megtekintéséhez. Az Apple HIG és a Google Material Design szerint a Pinch-to-Zoom egy alapvető gesztus, amelyet a felhasználók elvárnak minden vizuális tartalommal dolgozó alkalmazásban.

Főbb pontok

  • Pinch-to-Zoom — egy multitouch gesztus két ujjal a tartalom skálázásához mobileszközökön.
  • iOS-ben a feldolgozás az UIPinchGestureRecognizer-en keresztül történik folyamatos követéssel: .began → .changed → .ended.
  • Android-ban a ScaleGestureDetector (a Support Library-ből) használatos onScale callback-kel a skála Matrix-on keresztüli frissítéséhez.
  • Az UIPinchGestureRecognizer rendelkezik scale (az előző állapothoz viszonyított együttható) és velocity (sebesség) tulajdonsággal.
  • A nagyítás korlátozásához a scale együttható clamp-je alkalmazandó a megadott min/max értékek között (általában 0.5–3.0).

Mi az a Pinch-to-Zoom?

Pinch-to-Zoom (csípés vagy szorítás) — egy multitouch gesztus, amely két ujjat használ a megjelenített tartalom skálájának megváltoztatásához. Az ujjak összehúzásakor (pinch close) a skála csökken, széttárásakor (pinch open) — nő. A gesztus folyamatos: a rendszer valós időben követi az ujjak közötti távolságot és köztes eseményeket generál, lehetővé téve az alkalmazás számára a skála zökkenőmentes frissítését.

A gesztus mechanikája két érintési pont közötti távolság kiszámításán alapul. Az iOS és Android az euklideszi távolságot használja: sqrt((x2-x1)² + (y2-y1)²). Az aktuális scale a jelenlegi távolság és a kezdeti távolság arányaként számítható ki. Ha a kezdeti távolság 100px volt és 150px lett — scale = 1.5 (50%-os növekedés). Az iOS a scale-t az előző állapothoz képest (delta) adja át, az Android — felhalmozott scale-t a ScaleGestureDetector-on keresztül.

A Google Material Design Guidelines szerint a Pinch-to-Zoom kötelező a képeket, térképeket vagy dokumentumokat megjelenítő alkalmazások számára. Az IT Sectr-nél ezt a gesztust UIPinchGestureRecognizer és ScaleGestureDetector segítségével implementáljuk minden vizuális tartalommal dolgozó projektben — a galériáktól a képszerkesztőkig.

Pinch-to-Zoom iOS-ben: UIPinchGestureRecognizer

UIPinchGestureRecognizer — az UIGestureRecognizer folyamatos alosztálya a csípés gesztus felismerésére. A diszkrét felismerőkkel (UITapGestureRecognizer) ellentétben események sorozatát generálja: .began (ujjak érintették a képernyőt), .changed (ujjak minden mozgása), .ended (ujjak felemelkedtek).

Kulcsfontosságú tulajdonságok: scale (CGFloat) — az ujjak közötti távolság relatív változása a gesztus kezdetétől; velocity (CGFloat) — a scale másodpercenkénti változásának sebessége. Kezdeti scale = 1.0. Az ujjak széttárásakor a scale nő (1.0 → 1.5 → 2.0), összehúzásakor — csökken (1.0 → 0.8 → 0.5). A velocity tulajdonság tehetetlenséghez használatos: .ended után a skálázás folytatása csillapítással animálható.

Az UIPinchGestureRecognizer támogatja a delegate tulajdonságot más felismerőkkel (pl. pan + pinch térképen) való egyidejű működéshez. A gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:) metódus true-t ad vissza, és mindkét gesztus párhuzamosan működik. Az Apple azt ajánlja, hogy az UIPinchGestureRecognizer-t konténer nézethez adjuk hozzá, ne egyedi elemekhez — ez leegyszerűsíti a skálázás pivot pontjának kiszámítását.

Pinch-to-Zoom Android-ban: ScaleGestureDetector

ScaleGestureDetector — egy osztály az Android Support Library-ből (android.view), amely a multitouch skálázás felismerésére szolgál. A GestureDetector.onFling-től eltérően a ScaleGestureDetector kifejezetten kétujjas nagyításhoz tervezték, és automatikusan kiszámítja a focusX, focusY (ujjak közötti középpont) és scaleFactor (skála delta az előző eseménytől) értékeket.

A ScaleGestureDetector az OnScaleGestureListener interfészen keresztül működik három metódussal: onScaleBegin(detector) (.began megfelelője), onScale(detector) (.changed megfelelője, boolean-t ad vissza — true, ha a skála elfogadva), onScaleEnd(detector) (.ended megfelelője). Tulajdonságok: scaleFactor — a skála szorzója az előző eseményhez képest (~1.01 lassú széttáráskor), focusX/focusY — az ujjak közötti középpont koordinátái.

A skála View-ra történő alkalmazásához általában Matrix-ot használnak: view.imageMatrix.postScale(scaleFactor, scaleFactor, focusX, focusY). A Matrix támogatja a transzformációk felhalmozását — minden postScale hívás egy új transzformációt ad a meglévőhöz. Fontos megjegyezni: a ScaleGestureDetector nem korlátozza a minimális/maximális skálát — ez a fejlesztő feladata. Az IT Sectr-nél a ScaleGestureDetector-t egyedi skála határokkal (0.5–3.0) és túllépés esetén visszatérési animációval alkalmazzuk.

Nagyítás korlátozása és pivot pont

A Pinch-to-Zoom implementációjában kritikus fontosságú a minimális és maximális skála korlátozása — enélkül a felhasználó a végtelenségig nagyíthatja a képet, vagy láthatatlanságig kicsinyítheti. Alapértékek: min = 0.5 (az eredeti méret 50%-a), max = 3.0 (300%). iOS-ben a korlátozás clamp segítségével történik: newScale = min(max(currentScale * gesture.scale, minScale), maxScale). Android-ban — postScale utáni ellenőrzéssel.

A pivot pont — az ujjak közötti középpont, amelyhez képest a skálázás történik. Az iOS automatikusan kiszámítja két érintés középpontját és átadja a location(in:) metóduson keresztül — a fejlesztőnek nem kell manuálisan kiszámítania a pivot-ot. Az Android focusX/focusY-t biztosít a ScaleGestureDetector-ban, de Matrix-on keresztüli alkalmazáskor a pivot a harmadik és negyedik argumentumként kerül átadásra a postScale(scaleFactor, scaleFactor, focusX, focusY) hívásban. Pivot pont nélkül a skálázás a bal felső sarokhoz (0,0) képest történik, ami a tartalom eltolódásához vezet nagyításkor.

Az IT Sectr tapasztalata szerint a pivot pont helyes kiszámítása a leggyakoribb hibaforrás a Pinch-to-Zoom bevezetésénél. Az esetek 90%-ában elegendő a GestureRecognizer és ScaleGestureDetector beépített koordinátáit használni, anélkül hogy a pivot-ot manuálisan számítanánk ki. Ha a tartalom eltolódik skálázáskor — ellenőrizze, hogy átadja-e a focusX/focusY-t a matrix.postScale() metódusnak.

Tehetetlenség nagyítás után

A gördülékeny felhasználói élmény érdekében a gesztus befejezése után tehetetlenség adható hozzá: iOS-ben — használja a velocity-t az UIPinchGestureRecognizer-ből a UIView.animate spring paramétereivel; Android-ban — OverScroller vagy ValueAnimator. A tehetetlenség nem lépheti át a min/max scale határokat — a végső érték spring visszatérési animációval levágásra kerül túllépés esetén.

Kódpéldák Swift-ben és Kotlin-ban

1. példa: Pinch-to-Zoom iOS-en (Swift)

UIPinchGestureRecognizer-t ad hozzá UIImageView-hez 0.5-től 3.0-ig terjedő skála korlátozással. Minimális implementációt mutat a felhalmozott skála megtartásával.

swift
import UIKit

class ZoomableImageViewController: UIViewController {

    @IBOutlet private var imageView: UIImageView!
    private var currentScale: CGFloat = 1.0
    private let minScale: CGFloat = 0.5
    private let maxScale: CGFloat = 3.0

    override func viewDidLoad() {
        super.viewDidLoad()

        let pinch = UIPinchGestureRecognizer(
            target: self,
            action: #selector(handlePinch(_:))
        )
        imageView.addGestureRecognizer(pinch)
        imageView.isUserInteractionEnabled = true
    }

    @objc private func handlePinch(_: UIPinchGestureRecognizer) {
        if gestureRecognizer.state == .began
            || gestureRecognizer.state == .changed {

            let newScale = currentScale * gestureRecognizer.scale
            imageView.transform = CGAffineTransform(
                scaleX: min(max(newScale, minScale), maxScale),
                y: min(max(newScale, minScale), maxScale)
            )
        }
        if gestureRecognizer.state == .ended {
            currentScale = min(max(
                currentScale * gestureRecognizer.scale,
                minScale
            ), maxScale)
            gestureRecognizer.scale = 1.0
        }
    }
}

Logika: .began/.changed állapotban a skála CGAffineTransform segítségével clamp-pel kerül alkalmazásra. .ended állapotban a scale visszaáll 1.0-ra, és a felhalmozott érték a currentScale-ben tárolódik. Ez megakadályozza a skála „sodródását" többszörös gesztusok esetén — minden új gesztus az aktuális állapotból indul. Képek esetén a CGAffineTransform helyett UIScrollView ajánlott minimumZoomScale/maximumZoomScale tulajdonságokkal.

2. példa: Pinch-to-Zoom Android-ban (Kotlin)

ImageView skálázását implementálja ScaleGestureDetector segítségével Matrix-szal. Megmutatja a pivot pont helyes kezelését és a skála korlátozását.

kotlin
import android.content.Context
import android.graphics.Matrix
import android.view.MotionEvent
import android.view.ScaleGestureDetector
import android.widget.ImageView

class PinchZoomImageView(context: Context) : ImageView(context) {

    private val matrix = Matrix()
    private var currentScale = 1f
    private val minScale = 0.5f
    private val maxScale = 3.0f

    private val scaleDetector =
        ScaleGestureDetector(context, ScaleListener())

    private inner class ScaleListener : ScaleGestureDetector.SimpleOnScaleGestureListener() {
        override fun onScale(detector: ScaleGestureDetector): Boolean {
            currentScale = (currentScale * detector.scaleFactor)
                .coerceIn(minScale, maxScale)
            matrix.postScale(
                currentScale,
                currentScale,
                detector.focusX,
                detector.focusY
            )
            imageMatrix = matrix
            return true
        }
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        scaleDetector.onTouchEvent(event)
        return true
    }
}

Az egyedi ImageView felülírja az onTouchEvent metódust, átadva az eseményeket a ScaleGestureDetector-nak. Az OnScaleListener.onScale() minden ujjmozgáskor meghívódik. detector.scaleFactor — delta (1.01 lassú széttáráskor). A currentScale coerceIn segítségével halmozódik fel a clamp-hez. A focusX/focusY — az ujjak közötti középpont, amely a postScale metódusnak kerül átadásra a helyes pivot skálázáshoz.

3. példa: UIScrollView nagyítás támogatással (iOS)

Az UIScrollView beépített Pinch-to-Zoom támogatással rendelkezik delegált segítségével. Ez az előnyben részesített módszer képek és dokumentumok esetén — a ScrollView automatikusan kezeli a skálát, a tehetetlenséget és a görgetést.

swift
class ScrollableImageViewController: UIViewController,
                                    UIScrollViewDelegate {

    @IBOutlet private var scrollView: UIScrollView!
    @IBOutlet private var imageView: UIImageView!

    override func viewDidLoad() {
        super.viewDidLoad()
        scrollView.minimumZoomScale = 0.5
        scrollView.maximumZoomScale = 3.0
        scrollView.delegate = self
    }

    func viewForZooming(in scrollView: UIScrollView) -> UIView? {
        return imageView
    }
}

Az UIScrollView önállóan létrehozza az UIPinchGestureRecognizer-t, kezeli a skálát CALayer transzformáción keresztül, és bounce effektust ad hozzá a határok túllépésekor. A kód a min/maxZoomScale beállítására és a viewForZooming visszaadására redukálódik. Az IT Sectr-nél az UIScrollView-t használjuk minden teljes képernyős képhez — ez ötszörösére csökkenti a kód mennyiségét a kézi UIPinchGestureRecognizer implementációhoz képest.

Gyakran ismételt kérdések

Miben különbözik a pinch a trackpad csípéstől?

Az érintőképernyőn a pinch két ujjat használ a köztük lévő távolság követésével. MacBook trackpad-en a nagyítás UIPinchGestureRecognizer segítségével van implementálva ugyanazokkal az állapotokkal (.began → .changed → .ended), de az érintések forrása a Force Touch-os trackpad, nem kapacitív képernyő. Az API ugyanaz, a mechanika azonos.

Hogyan korlátozhatom a minimális és maximális nagyítást?

iOS-ben: az UIPinchGestureRecognizer scale értékének megszerzése után szorozza meg a currentScale-lel és alkalmazza a clamp(min: 0.5, max: 3.0) függvényt. Android-ban: a coerceIn(minScale, maxScale) segítségével a matrix.postScale() előtt. UIScrollView-ben — a minimumZoomScale és maximumZoomScale tulajdonságokon keresztül. Korlátozás nélkül a skála a végtelenbe vagy nullába mehet.

Működik a Pinch-to-Zoom egy ujjal?

Nem, a pinch legalább két ujjat igényel. Az egyujjas nagyításhoz (double-tap + húzás felfelé/lefelé) egyedi implementáció szükséges UIPanGestureRecognizer vagy GestureDetector.onScroll segítségével. Ez egy másik gesztus eltérő logikával — általában kamera vagy térképek nagyításához használatos.

Összefoglalás

  • Pinch-to-Zoom — egy multitouch gesztus két ujjal a tartalom skálázásához, szabvány képekhez, térképekhez és dokumentumokhoz.
  • UIPinchGestureRecognizer iOS-ben — folyamatos felismerő scale (delta) és velocity (sebesség) tulajdonságokkal.
  • ScaleGestureDetector Android-ban — specializált detektor onScale(), focusX/focusY metódusokkal a pivot ponthoz.
  • UIScrollView esetén a nagyítás a minimumZoomScale/maximumZoomScale segítségével építhető be — egyszerűbb, mint a kézi implementáció.
  • Kötelezően korlátozza a skálát (0.5–3.0) clamp segítségével — enélkül a tartalom láthatatlanná válhat.
  • A skálázás pivot pontja — az ujjak közötti középpont; nélküle a tartalom eltolódik nagyításkor.
  • Az IT Sectr-nél UIScrollView-t használunk képekhez és egyedi ScaleGestureDetector-t szerkesztőkhöz — a választás a transzformációk összetettségétől függ.

Kulcsrakész mobilalkalmazást fejlesztünk

Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.

Projekt megbeszélése

Olvassa el is