Huvudpunkter
Svep — en snabb glidande rörelse av fingret över skärmytan som slutar med att fingret lyfts. Svep kan vara kort (skrolling av ett element) eller långt (öppning av en gardin), men nyckelegenskapen är diskretion: systemet känner igen det som en enskild händelse, inte som en kontinuerlig sekvens av koordinater.
Mobila operativsystem bestämmer svep baserat på tre parametrar: minsta avstånd (tröskel), minsta hastighet (velocity) och riktning. Om fingret rör sig långsamt eller avståndet är otillräckligt tolkar systemet gesten som panorering (pan) eller tap. Tröskelvärden skiljer sig mellan plattformar: iOS använder konstanten UISwipeGestureRecognizer med fast tröskel, Android — ViewConfiguration.getScaledTouchSlop(), som returnerar ~8–16 dp beroende på skärmdensitet.
Enligt Android Developers Documentation aktiveras onFling (svep) i GestureDetector vid hastighet över 100 px/s och avstånd från 50px. På IT Sectr använder vi svep för navigering (gallerier, kortgränssnitt, onboarding) — denna gest är intuitiv för användare i alla åldrar.
Svep och panorering (pan/drag) — olika typer av gester, även om båda använder fingerrörelse på skärmen. Svep är diskret och betyder „urför en åtgärd”, medan panorering är kontinuerlig och betyder „flytta objektet medan fingret är på skärmen”.
| Parameter | Svep | Panorering (Pan/Drag) |
|---|---|---|
| Typ | Diskret | Kontinuerlig |
| Händelse | En (igenkänd/ej igenkänd) | Flera (.began → .changed → .ended) |
| Hastighet | Hög (snabb rörelse) | Valfri (långsam rörelse) |
| Exempel iOS | UISwipeGestureRecognizer | UIPanGestureRecognizer |
| Exempel Android | GestureDetector.onFling() | GestureDetector.onScroll() |
| Scenario | Ta bort e-post, bläddra sida | Flytta karta, dra fil |
| Koordinatspårning | Nej (endast riktning) | Ja (kontinuerlig koordinatuppdatering) |
Valet mellan svep och panorering beror på uppgiften. För åtgärder på ett element (ta bort, arkivera, öppna meny) använd svep. För direkt manipulering (flytta, skala) — panorering. Blandning av gester på samma element kräver require(toFail:) eller anpassad logik.
UISwipeGestureRecognizer — en underklass av UIGestureRecognizer som känner igen diskret svep i en av fyra riktningar. Till skillnad från UIPanGestureRecognizer genererar den inte mellanliggande .changed-händelser: vid igenkänning anropas action exakt en gång.
Egenskapen direction (UISwipeGestureRecognizer.Direction) anger spårad riktning — .left, .right, .up, .down. Kan kombineras via mask: [.left, .right] för horisontella svep. Egenskapen numberOfTouchesRequired bestämmer antal fingrar — standard 1. UISwipeGestureRecognizer har ingen konfigurerbar avståndströskel — iOS använder inbyggt värde på cirka 20px, tillräckligt för tillförlitlig igenkänning.
Eftersom UISwipeGestureRecogniser är en diskret igenkännare kolliderar den inte med UIPanGestureRecognizer: vid långsam rörelse aktiveras pan, vid snabb — swipe. Vid samexistens med UITapGestureRecognizer på samma vy kan require(toFail:) krävas för att förhindra falsk tap-igenkänning.
I Android är huvud-API:t för svepigenkänning GestureDetector med callback OnGestureListener, nämligen metoden onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY). GestureDetector analyserar fingrets start- och slutposition, rörelsehastighet längs axlarna och avstånd, och anropar sedan onFling när trösklar överskrids.
Minsta trösklar konfigureras via ViewConfiguration: VelocityTracker.getMinVelocity() (~100 px/s) och ViewConfiguration.getScaledTouchSlop() (~8–16 dp). Anpassad OnSwipeTouchListener — ett vanligt mönster som förenklar API:t: utvecklaren behöver inte manuellt beräkna riktning och hastighet. Android Support Library innehåller ingen inbyggd „SwipeDetector”, så en anpassad wrapper är standardlösningen.
För svep i listor rekommenderar Google att använda ItemTouchHelper.SimpleCallback från RecyclerView, som abstraherar gestdetektering, animation och onSwiped()-callbacks. På IT Sectr använder vi anpassad SwipeListener för ViewPager2 och kortgränssnitt — detta ger kontroll över svepkänslighet utan att påverka prestanda.
För listor (UITableView, RecyclerView) tillhandahåller Apple och Google specialiserade API:er som ersätter manuell tilläggning av UISwipeGestureRecognizer. Dessa API:er stöder åtgärdsknappar, anpassad animation och „svep för att ta bort”-gester — standardmönster för mobilappar.
I iOS (11+) används UISwipeActionsConfiguration: metoden tableView(_:leadingSwipeActionsConfigurationForRowAt:) returnerar en array av UIContextualAction — knappar med titel, stil (destructive, normal) och hanterare. Till exempel „Ta bort” — .destructive med röd bakgrund, „Arkiv” — .normal med grå. Systemet animerar själv knapparnas uppkomst och anropar completion-blocket efter tryckning.
I Android fästs ItemTouchHelper.SimpleCallback på RecyclerView via ItemTouchHelper.attachToRecyclerView(). Parametrar — riktningsflaggor (start, end, up, down) och callback onSwiped(viewHolder, direction). Inuti onSwiped anropas adapter.notifyItemRemoved(position) för att ta bort elementet med animation. ItemTouchHelper hanterar automatiskt gester, konflikter med scrollning och återlämning av element om svepet inte slutförs. Enligt Google I/O 2024 används ItemTouchHelper i 70% av Android-appar med svepåtgärder i listor.
Lägger till UISwipeGestureRecognizer på vyn för att återgå till föregående skärm. Koden visar minimal konfiguration av igenkännaren med riktning .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)
}
}
}
Igenkännaren kopplas till kontrollerns root-vy. Kontroll av navigationController.viewControllers.count garanterar att pop endast utförs när det finns en föregående skärm i stacken. För modala kontrollanter används dismiss. Koden kräver ingen tillståndskontroll — UISwipeGestureRecognizer är diskret och anropar action endast vid lyckad igenkänning.
Implementerar en enkel wrapper för GestureDetector som bestämmer svepriktning och anropar onSwipeLeft/Right-callbacks.
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 utökar SimpleOnGestureListener och implementerar onFling. diffX/diffY bestämmer riktning, SWIPE_THRESHOLD (100px) och SWIPE_VELOCITY_THRESHOLD (100 px/s) — trösklar. Användning: view.setOnTouchListener(OnSwipeTouchListener(context).apply { onSwipeLeft = { dismiss() } }).
Lägger till en borttagningsknapp vid svep åt vänster på en tabellcell. Använder inbyggt API för iOS 11+ utan manuell gestigenkänning.
func tableView(
_ tableView: UITableView,
trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath
) -> UISwipeActionsConfiguration? {
let deleteAction = UIContextualAction(
style: .destructive,
title: "Ta bort"
) { _, _, 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
}
Metoden returnerar UISwipeActionsConfiguration med en array av UIContextualAction. style: .destructive ställer automatiskt in röd bakgrund. performsFirstActionWithFullSwipe = true gör det möjligt att utföra åtgärden med fullt svep utan ytterligare tryckning. På IT Sectr använder vi detta API för alla listor med åtgärder — det är standardiserat, stöder VoiceOver och kräver inga anpassade GestureRecognizer.
Vanliga frågor
Svep — diskret gest med snabb rörelse och fingerlyft, panorering — kontinuerlig dragning med koordinatspårning. UISwipeGestureRecognizer aktiveras en gång, UIPanGestureRecognizer genererar .began → .changed → .ended. Valet beror på scenario: svep — för åtgärder (ta bort, bläddra), pan — för förflyttning (karta, reglage).
Gestlogiken är identisk, men API:t skiljer sig. iOS använder UISwipeGestureRecognizer med direction. Android använder GestureDetector.onFling() med anpassade trösklar. Resultatet — samma UX med olika implementering. Plattformsoberoende ramverk (Flutter, React Native) abstraherar skillnaden via ett enhetligt svep-API.
I iOS (11+) använd UISwipeActionsConfiguration i UITableViewDelegate. I Android — ItemTouchHelper.SimpleCallback för RecyclerView. Dessa API:er ersätter manuella GestureRecognizer, stöder åtgärdsknappar och animation, hanterar korrekt konflikt med scrollning och anpassar sig till plattformens HIG.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också