Hlavní body
Swipe je rychlý klouzavý pohyb prstem po povrchu obrazovky, končící zvednutím. Swipe může být krátký (posouvání prvku) nebo dlouhý (otevření závěsu), ale klíčovou charakteristikou je diskrétnost: systém ho rozpozná jako jednu událost, ne jako nepřetržitou sekvenci souřadnic.
Mobilní OS určují swipe podle tří parametrů: minimální vzdálenost (práh), minimální rychlost (velocity) a směr. Pokud se prst pohybuje pomalu nebo vzdálenost není dostatečná, systém interpretuje gesto jako posouvání (pan) nebo tap. Prahové hodnoty se liší mezi platformami: iOS používá konstantu UISwipeGestureRecognizer s pevným prahem, Android — ViewConfiguration.getScaledTouchSlop(), vracející ~8–16 dp v závislosti na hustotě obrazovky.
Podle Android Developers Documentation se onFling (swipe) v GestureDetector aktivuje při rychlosti nad 100 px/s a vzdálenosti od 50px. V IT Sectr používáme swipe pro navigaci (galerie, karetní rozhraní, onboarding) — toto gesto je intuitivní pro uživatele všech věkových kategorií.
Swipe a posouvání (pan/drag) jsou různé typy gest, ačkoli obě používají pohyb prstu po obrazovce. Swipe je diskrétní a znamená „proveď jednu akci”, zatímco posouvání je nepřetržité a znamená „přesouvej objekt, dokud je prst na obrazovce”.
| Parametr | Swipe | Posouvání (Pan/Drag) |
|---|---|---|
| Typ | Diskrétní | Nepřetržitý |
| Události | Jedna (rozpoznáno/nerozpoznáno) | Více (.began → .changed → .ended) |
| Rychlost | Vysoká (rychlý pohyb) | Jakákoli (pomalý pohyb) |
| Příklad iOS | UISwipeGestureRecognizer | UIPanGestureRecognizer |
| Příklad Android | GestureDetector.onFling() | GestureDetector.onScroll() |
| Scénář | Smazat email, otočit stránku | Přesunout mapu, přetáhnout soubor |
| Sledování souřadnic | Ne (jen směr) | Ano (průběžná aktualizace souřadnic) |
Výběr mezi swipe a posouváním závisí na úkolu. Pro akce s prvkem (smazat, archivovat, otevřít menu) použijte swipe. Pro přímou manipulaci (přesun, škálování) — posouvání. Míchání gest na jednom prvku vyžaduje require(toFail:) nebo vlastní logiku.
UISwipeGestureRecognizer je podtřída UIGestureRecognizer, která rozpoznává diskrétní swipe v jednom ze čtyř směrů. Na rozdíl od UIPanGestureRecognizer negeneruje průběžné události .changed: při rozpoznání se action volá přesně jednou.
Vlastnost direction (UISwipeGestureRecognizer.Direction) nastavuje sledovaný směr — .left, .right, .up, .down. Lze kombinovat přes masku: [.left, .right] pro horizontální swipy. Vlastnost numberOfTouchesRequired určuje počet prstů — výchozí 1. UISwipeGestureRecognizer nemá nastavitelný práh vzdálenosti — iOS používá vestavěnou hodnotu asi 20px, dostatečnou pro spolehlivé rozpoznání.
Protože UISwipeGestureRecogniser je diskrétní rozpoznávač, nekoliduje s UIPanGestureRecognizer: při pomalém pohybu se aktivuje pan, při rychlém — swipe. Při souběhu s UITapGestureRecognizer na stejném view však může být vyžadováno require(toFail:) k zabránění falešnému rozpoznání tapu.
V Android je hlavní API pro rozpoznání swipe GestureDetector s callbackem OnGestureListener, konkrétně metoda onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY). GestureDetector analyzuje počáteční a koncovou polohu prstu, rychlost pohybu po osách a vzdálenost, poté volá onFling při překročení prahů.
Minimální prahy se nastavují přes ViewConfiguration: VelocityTracker.getMinVelocity() (~100 px/s) a ViewConfiguration.getScaledTouchSlop() (~8–16 dp). Vlastní OnSwipeTouchListener je běžný vzor zjednodušující API: vývojář nemusí ručně počítat směr a rychlost. Android Support Library neobsahuje vestavěný „SwipeDetector”, takže vlastní obálka je standardním řešením.
Pro swipe v seznamech Google doporučuje použít ItemTouchHelper.SimpleCallback z RecyclerView, který abstrahuje detekci gesta, animaci a callbacky onSwiped(). V IT Sectr používáme vlastní SwipeListener pro ViewPager2 a karetní rozhraní — to poskytuje kontrolu nad citlivostí swipe bez dopadu na výkon.
Pro seznamy (UITableView, RecyclerView) Apple a Google poskytují specializovaná API, která nahrazují ruční přidávání UISwipeGestureRecognizer. Tato API podporují tlačítka akcí, vlastní animaci a gesta „přejeďte pro smazání” — standardní vzory mobilních aplikací.
V iOS (11+) se používá UISwipeActionsConfiguration: metoda tableView(_:leadingSwipeActionsConfigurationForRowAt:) vrací pole UIContextualAction — tlačítek s názvem, stylem (destructive, normal) a handlerem. Například „Smazat” — .destructive s červeným pozadím, „Archiv” — .normal s šedým. Systém sám animuje zobrazení tlačítek a volá completion blok po stisknutí.
V Android je ItemTouchHelper.SimpleCallback připojen k RecyclerView přes ItemTouchHelper.attachToRecyclerView(). Parametry — příznaky směru (start, end, up, down) a callback onSwiped(viewHolder, direction). Uvnitř onSwiped je voláno adapter.notifyItemRemoved(position) pro odstranění prvku s animací. ItemTouchHelper automaticky zpracovává gesta, konflikty s rolováním (scroll) a vracení prvku, pokud swipe není dokončen. Podle Google I/O 2024 je ItemTouchHelper používán v 70% Android aplikací s akcemi přejetí v seznamech.
Přidává UISwipeGestureRecognizer na view pro návrat k předchozí obrazovce. Kód ukazuje minimální konfiguraci rozpoznávače se směrem .left.
import UIKit
class CardViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let swipeLeft = UISwipeGestureRecognizer(
target: self,
action: #selector(handleSwipeLeft(_:))
)
swipeLeft.direction = .left
swipeLeft.numberOfTouchesRequired = 1
view.addGestureRecognizer(swipeLeft)
}
@objc private func handleSwipeLeft(_: UISwipeGestureRecognizer) {
guard let nav = navigationController else { return }
if nav.viewControllers.count > 1 {
nav.popViewController(animated: true)
} else {
nav.dismiss(animated: true)
}
}
}
Rozpoznávač se připojuje k root-view kontroleru. Kontrola navigationController.viewControllers.count zaručuje, že pop se provádí jen při existenci předchozí obrazovky v zásobníku. Pro modální kontrolery se používá dismiss. Kód nevyžaduje kontrolu stavu — UISwipeGestureRecognizer je diskrétní a volá action pouze při úspěšném rozpoznání.
Implementuje jednoduchou obálku GestureDetector, která určuje směr přejetí a volá callbacky onSwipeLeft/Right.
import android.content.Context
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.View
open class OnSwipeTouchListener(context: Context) : View.OnTouchListener {
private val gestureDetector = GestureDetector(context, GestureListener())
override fun onTouch(v: View, event: MotionEvent): Boolean {
return gestureDetector.onTouchEvent(event)
}
private inner class GestureListener : GestureDetector.SimpleOnGestureListener() {
companion object {
private const val SWIPE_THRESHOLD = 100
private const val SWIPE_VELOCITY_THRESHOLD = 100
}
override fun onFling(
e1: MotionEvent?,
e2: MotionEvent,
velocityX: Float,
velocityY: Float
): Boolean {
val diffX = e2.x - e1!!.x
val diffY = e2.y - e1.y
if (Math.abs(diffX) > Math.abs(diffY)) {
if (Math.abs(diffX) > SWIPE_THRESHOLD
&& Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD
) {
if (diffX > 0) onSwipeRight()
else onSwipeLeft()
return true
}
} else {
if (Math.abs(diffY) > SWIPE_THRESHOLD
&& Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD
) {
if (diffY > 0) onSwipeDown()
else onSwipeUp()
return true
}
}
return false
}
}
open fun onSwipeLeft() {}
open fun onSwipeRight() {}
open fun onSwipeUp() {}
open fun onSwipeDown() {}
}
OnSwipeTouchListener rozšiřuje SimpleOnGestureListener, implementující onFling. diffX/diffY určují směr, SWIPE_THRESHOLD (100px) a SWIPE_VELOCITY_THRESHOLD (100 px/s) — prahy. Použití: view.setOnTouchListener(OnSwipeTouchListener(context).apply { onSwipeLeft = { dismiss() } }).
Přidává tlačítko smazání při přejetí doleva po buňce tabulky. Používá vestavěné API iOS 11+ bez ručního rozpoznávání gest.
func tableView(
_ tableView: UITableView,
trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath
) -> UISwipeActionsConfiguration? {
let deleteAction = UIContextualAction(
style: .destructive,
title: "Smazat"
) { _, _, completionHandler in
items.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .automatic)
completionHandler(true)
}
deleteAction.backgroundColor = .systemRed
let config = UISwipeActionsConfiguration(actions: [deleteAction])
config.performsFirstActionWithFullSwipe = true
return config
}
Metoda vrací UISwipeActionsConfiguration s polem UIContextualAction. style: .destructive automaticky nastaví červené pozadí. performsFirstActionWithFullSwipe = true umožňuje provést akci plným přejetím bez dalšího stisknutí. V IT Sectr používáme toto API pro všechny seznamy s akcemi — je standardizované, podporuje VoiceOver a nevyžaduje vlastní GestureRecognizer.
Často kladené otázky
Swipe je diskrétní gesto s rychlým pohybem a zvednutím prstu, posouvání je nepřetržité tažení se sledováním souřadnic. UISwipeGestureRecognizer se aktivuje jednou, UIPanGestureRecognizer generuje .began → .changed → .ended. Volba závisí na scénáři: swipe — pro akce (smazat, otočit), pan — pro přesun (mapa, posuvník).
Logika gesta je identická, ale API se liší. iOS používá UISwipeGestureRecognizer s direction. Android používá GestureDetector.onFling() s vlastními prahy. Výsledek — stejné UX při různé implementaci. Cross-platform frameworky (Flutter, React Native) abstrahují rozdíl přes jednotné API swipe.
V iOS (11+) použijte UISwipeActionsConfiguration v UITableViewDelegate. V Android — ItemTouchHelper.SimpleCallback pro RecyclerView. Tato API nahrazují ruční GestureRecognizer, podporují tlačítka akcí a animaci, správně zpracovávají konflikt s rolováním a přizpůsobují se platformovým HIG.
Shrnutí
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í.
Přečtěte si také