Pinch-to-Zoom — podstata, zpracování štípnutí v mobilních aplikacích

Autor: IT Sectr Publikováno: 2026-02-27 Doba čtení: 8 min
Pinch-to-Zoom (štípnutí prsty) — multi-touch gesto škálování, při kterém uživatel přibližuje nebo oddaluje dva prsty na obrazovce pro zmenšení nebo zvětšení obsahu. Toto gesto se stalo de facto standardem pro prohlížení obrázků, map, webových stránek a dokumentů na mobilních zařízeních. Podle Apple HIG a Google Material Design je Pinch-to-Zoom základní gesto, které uživatelé očekávají ve všech aplikacích pracujících s vizuálním obsahem.

Hlavní body

  • Pinch-to-Zoom — multi-touch gesto se dvěma prsty pro škálování obsahu na mobilních zařízeních.
  • V iOS je zpracování prováděno přes UIPinchGestureRecognizer s kontinuálním sledováním .began → .changed → .ended.
  • V Android se používá ScaleGestureDetector (z Support Library) s callbackem onScale pro aktualizaci měřítka přes Matrix.
  • UIPinchGestureRecognizer má vlastnost scale (koeficient vůči předchozímu stavu) a velocity (rychlost).
  • Pro omezení zoomu se aplikuje clamp koeficientu scale mezi zadanými min/max hodnotami (obvykle 0.5–3.0).

Co je Pinch-to-Zoom?

Pinch-to-Zoom (štípnutí nebo stisknutí) — multi-touch gesto, které používá dva prsty ke změně měřítka zobrazeného obsahu. Při přibližování prstů (pinch close) se měřítko zmenšuje, při oddalování (pinch open) — zvětšuje. Gesto je kontinuální: systém sleduje vzdálenost mezi prsty v reálném čase a generuje mezilehlé události, což aplikaci umožňuje plynule aktualizovat měřítko.

Mechanika gesta je založena na výpočtu vzdálenosti mezi dvěma body dotyku. iOS a Android používají euklidovskou vzdálenost: sqrt((x2-x1)² + (y2-y1)²). Aktuální scale se vypočítá jako poměr aktuální vzdálenosti k počáteční. Pokud byla počáteční vzdálenost 100px a stala se 150px — scale = 1.5 (zvýšení o 50%). iOS předává scale vůči předchozímu stavu (delta), Android — akumulovaný scale přes ScaleGestureDetector.

Podle Google Material Design Guidelines je Pinch-to-Zoom povinný pro aplikace zobrazující obrázky, mapy nebo dokumenty. V IT Sectr implementujeme toto gesto pomocí UIPinchGestureRecognizer a ScaleGestureDetector ve všech projektech pracujících s vizuálním obsahem — od galerií po editory obrázků.

Pinch-to-Zoom v iOS: UIPinchGestureRecognizer

UIPinchGestureRecognizer — kontinuální podtřída UIGestureRecognizer pro rozpoznávání gesta štípnutí. Na rozdíl od diskrétních rozpoznávačů (UITapGestureRecognizer) generuje sekvenci událostí: .began (prsty se dotkly obrazovky), .changed (každý pohyb prstů), .ended (prsty zvednuty).

Klíčové vlastnosti: scale (CGFloat) — relativní změna vzdálenosti mezi prsty od začátku gesta; velocity (CGFloat) — rychlost změny scale za sekundu. Počáteční scale = 1.0. Při oddalování prstů scale roste (1.0 → 1.5 → 2.0), při přibližování — klesá (1.0 → 0.8 → 0.5). Vlastnost velocity se používá pro setrvačnost: po .ended lze animovat pokračování škálování s útlumem.

UIPinchGestureRecognizer podporuje vlastnost delegate pro současnou práci s jinými rozpoznávači (např. pan + pinch na mapě). Metoda gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:) vrací true a obě gesta pracují paralelně. Apple doporučuje přidávat UIPinchGestureRecognizer na kontejnerový view, ne na jednotlivé prvky — to zjednodušuje výpočet pivot bodu škálování.

Pinch-to-Zoom v Android: ScaleGestureDetector

ScaleGestureDetector — třída z Android Support Library (android.view), určená pro rozpoznávání multi-touch škálování. Na rozdíl od GestureDetector.onFling je ScaleGestureDetector speciálně navržen pro zoom dvěma prsty a automaticky vypočítává focusX, focusY (střed mezi prsty) a scaleFactor (delta měřítka od předchozí události).

ScaleGestureDetector pracuje přes rozhraní OnScaleGestureListener se třemi metodami: onScaleBegin(detector) (ekvivalent .began), onScale(detector) (ekvivalent .changed, vrací boolean — true pokud je měřítko přijato), onScaleEnd(detector) (ekvivalent .ended). Vlastnosti: scaleFactor — násobitel měřítka vůči předchozí události (~1.01 při pomalém oddalování), focusX/focusY — souřadnice středu mezi prsty.

Pro aplikaci měřítka na View se obvykle používá Matrix: view.imageMatrix.postScale(scaleFactor, scaleFactor, focusX, focusY). Matrix podporuje akumulaci transformací — každé volání postScale přidává novou transformaci ke stávající. Důležité: ScaleGestureDetector neomezuje minimální/maximální měřítko — to je úkolem vývojáře. V IT Sectr aplikujeme ScaleGestureDetector s vlastními hranicemi scale (0.5–3.0) a animací návratu při překročení.

Omezení zoomu a pivot bod

Při implementaci Pinch-to-Zoom je kriticky důležité omezit minimální a maximální měřítko — bez toho může uživatel zvětšit obrázek do nekonečna nebo jej zmenšit do neviditelnosti. Standardní hodnoty: min = 0.5 (50% původní velikosti), max = 3.0 (300%). V iOS se omezení provádí přes clamp: newScale = min(max(currentScale * gesture.scale, minScale), maxScale). V Android — přes kontrolu po postScale.

Pivot bod — střed mezi prsty, vůči kterému se provádí škálování. iOS automaticky vypočítá centroid dvou dotyků a předá jej přes location(in:) — vývojář nemusí počítat pivot ručně. Android poskytuje focusX/focusY v ScaleGestureDetector, ale při aplikaci přes Matrix se pivot předává jako třetí a čtvrtý argument v postScale(scaleFactor, scaleFactor, focusX, focusY). Bez pivot bodu se škálování provádí vůči levému hornímu rohu (0,0), což vede k posunu obsahu při zoomu.

Podle zkušeností IT Sectr je správný výpočet pivot bodu nejčastějším zdrojem chyb při zavádění Pinch-to-Zoom. V 90% případů stačí použít vestavěné souřadnice GestureRecognizer a ScaleGestureDetector, bez ručního výpočtu pivotu. Pokud se obsah při škálování posouvá — zkontrolujte, zda předáváte focusX/focusY do matrix.postScale().

Setrvačnost po zoomu

Pro plynulé UX po dokončení gesta lze přidat setrvačnost: v iOS — použijte velocity z UIPinchGestureRecognizer pro UIView.animate s parametry spring; v Android — OverScroller nebo ValueAnimator. Setrvačnost by neměla překračovat hranice min/max scale — konečná hodnota je oříznuta s spring animací návratu při překročení.

Příklady kódu ve Swift a Kotlin

Příklad 1: Pinch-to-Zoom na iOS (Swift)

Přidává UIPinchGestureRecognizer na UIImageView s omezením měřítka od 0.5 do 3.0. Ukazuje minimální implementaci s uchováním akumulovaného měřítka.

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: v .began/.changed se měřítko aplikuje přes CGAffineTransform s clamp. V .ended se scale resetuje na 1.0 a akumulovaná hodnota se uloží do currentScale. To zabraňuje "driftu" měřítka při vícenásobných gestech — každé nové gesto začíná z aktuálního stavu. Pro obrázky se místo CGAffineTransform doporučuje UIScrollView s minimumZoomScale/maximumZoomScale.

Příklad 2: Pinch-to-Zoom na Android (Kotlin)

Implementuje škálování ImageView přes ScaleGestureDetector s Matrix. Ukazuje správné zpracování pivot bodu a omezení měřítka.

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
    }
}

Vlastní ImageView přepisuje onTouchEvent a předává události ScaleGestureDetector. OnScaleListener.onScale() se volá při každém pohybu prstů. detector.scaleFactor — delta (1.01 při pomalém oddalování). currentScale se akumuluje s coerceIn pro clamp. focusX/focusY — střed mezi prsty, předaný do postScale pro správné pivot škálování.

Příklad 3: UIScrollView s podporou zoomu (iOS)

UIScrollView má vestavěnou podporu Pinch-to-Zoom přes delegáta. Toto je preferovaný způsob pro obrázky a dokumenty — ScrollView spravuje měřítko, setrvačnost a posouvání automaticky.

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
    }
}

UIScrollView samostatně vytváří UIPinchGestureRecognizer, spravuje měřítko pomocí CALayer transformace a přidává bounce efekt při překročení hranic. Kód se redukuje na nastavení min/maxZoomScale a vrácení viewForZooming. V IT Sectr používáme UIScrollView pro všechny celoobrazovkové obrázky — to 5krát snižuje objem kódu ve srovnání s ruční implementací přes UIPinchGestureRecognizer.

Často kladené otázky

Čím se pinch liší od štípnutí na trackpadu?

Na dotykové obrazovce pinch používá dva prsty se sledováním vzdálenosti mezi nimi. Na trackpadu MacBook je škálování implementováno přes UIPinchGestureRecognizer se stejnými stavy (.began → .changed → .ended), ale zdrojem dotyků je trackpad s Force Touch, nikoli kapacitní obrazovka. API je stejné, mechanika identická.

Jak omezit minimální a maximální zoom?

V iOS: po získání scale z UIPinchGestureRecognizer vynásobte currentScale a aplikujte clamp(min: 0.5, max: 3.0). V Android: přes coerceIn(minScale, maxScale) před matrix.postScale(). V UIScrollView — přes vlastnosti minimumZoomScale a maximumZoomScale. Bez omezení může měřítko jít do nekonečna nebo nuly.

Funguje Pinch-to-Zoom s jedním prstem?

Ne, pinch vyžaduje minimálně dva prsty. Pro zoom jedním prstem (double-tap + tažení nahoru/dolů) je vyžadována vlastní implementace přes UIPanGestureRecognizer nebo GestureDetector.onScroll. Toto je jiné gesto s jinou logikou — obvykle se používá pro zoom v kameře nebo mapách.

Shrnutí

  • Pinch-to-Zoom — multi-touch gesto se dvěma prsty pro škálování obsahu, standard pro obrázky, mapy a dokumenty.
  • UIPinchGestureRecognizer v iOS — kontinuální rozpoznávač s scale (delta) a velocity (rychlost).
  • ScaleGestureDetector v Android — specializovaný detektor s onScale(), focusX/focusY pro pivot bod.
  • Pro UIScrollView se zoom vkládá přes minimumZoomScale/maximumZoomScale — jednodušší než ruční implementace.
  • Povinně omezte měřítko (0.5–3.0) přes clamp — bez toho může být obsah neviditelný.
  • Pivot bod škálování — střed mezi prsty; bez něj se obsah při zvětšování posouvá.
  • V IT Sectr používáme UIScrollView pro obrázky a vlastní ScaleGestureDetector pro editory — volba závisí na složitosti transformací.

Vyvineme mobilní aplikaci na klíč

IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.

Prodiskutovat projekt

Přečtěte si také