Mga pangunahing punto
Swipe ay isang mabilis na paggalaw ng pag-slide ng daliri sa ibabaw ng screen na nagtatapos sa pag-angat. Ang swipe ay maaaring maikli (pag-scroll ng elemento) o mahaba (pagbubukas ng kurtina), ngunit ang pangunahing katangian ay diskreto: kinikilala ito ng system bilang isang kaganapan, hindi bilang isang tuloy-tuloy na pagkakasunod-sunod ng mga coordinate.
Tinutukoy ng mga mobile OS ang swipe batay sa tatlong parameter: pinakamababang distansya (threshold), pinakamababang bilis (velocity) at direksyon. Kung ang daliri ay gumagalaw nang mabagal o hindi sapat ang distansya, binibigyang-kahulugan ng system ang kilos bilang pan o tap. Ang mga halaga ng threshold ay naiiba sa pagitan ng mga platform: iOS ay gumagamit ng constant UISwipeGestureRecognizer na may nakapirming threshold, Android — ViewConfiguration.getScaledTouchSlop(), na nagbabalik ng ~8–16 dp depende sa density ng screen.
Ayon sa Android Developers Documentation, ang onFling (swipe) sa GestureDetector ay nag-a-activate sa bilis na higit sa 100 px/s at distansya mula 50px. Sa IT Sectr ginagamit namin ang swipe para sa nabigasyon (mga gallery, card interface, onboarding) — ang kilos na ito ay intuitive para sa mga gumagamit sa lahat ng edad.
Swipe at pan (pan/drag) ay magkaibang uri ng mga kilos, bagaman pareho silang gumagamit ng paggalaw ng daliri sa screen. Ang swipe ay diskreto at nangangahulugang „gumawa ng isang aksyon”, samantalang ang pan ay tuloy-tuloy at nangangahulugang „ilipat ang bagay habang nasa screen ang daliri”.
| Parameter | Swipe | Pan (Pan/Drag) |
|---|---|---|
| Uri | Diskreto | Tuloy-tuloy |
| Mga Kaganapan | Isa (kinikilala/hindi kinikilala) | Marami (.began → .changed → .ended) |
| Bilis | Mataas (mabilis na paggalaw) | Kahit ano (mabagal na paggalaw) |
| Halimbawa iOS | UISwipeGestureRecognizer | UIPanGestureRecognizer |
| Halimbawa Android | GestureDetector.onFling() | GestureDetector.onScroll() |
| Scenario | Tanggalin ang email, ibalik ang pahina | Ilipat ang mapa, i-drag ang file |
| Pagsubaybay ng coordinate | Hindi (direksyon lamang) | Oo (patuloy na pag-update ng coordinate) |
Ang pagpili sa pagitan ng swipe at pan ay nakadepende sa gawain. Para sa mga aksyon sa elemento (tanggalin, archive, buksan ang menu) gamitin ang swipe. Para sa direktang manipulasyon (paglipat, pag-scale) — pan. Ang paghahalo ng mga kilos sa isang elemento ay nangangailangan ng require(toFail:) o custom na lohika.
UISwipeGestureRecognizer ay isang subclass ng UIGestureRecognizer na kumikilala ng diskretong swipe sa isa sa apat na direksyon. Hindi tulad ng UIPanGestureRecognizer, hindi ito bumubuo ng mga intermediate .changed na kaganapan: sa pagkilala, ang action ay tinatawag nang eksaktong isang beses.
Ang property na direction (UISwipeGestureRecognizer.Direction) ay nagtatakda ng sinusubaybayang direksyon — .left, .right, .up, .down. Maaaring pagsamahin sa pamamagitan ng mask: [.left, .right] para sa horizontal na swipe. Ang property na numberOfTouchesRequired ay tumutukoy sa bilang ng mga daliri — default 1. Ang UISwipeGestureRecognizer ay walang nako-configure na distance threshold — gumagamit ang iOS ng built-in na halaga na mga 20px, sapat para sa maaasahang pagkilala.
Dahil ang UISwipeGestureRecogniser ay isang diskretong tagakilala, hindi ito nagkakasalungat sa UIPanGestureRecognizer: sa mabagal na paggalaw ay mag-a-activate ang pan, sa mabilis — swipe. Gayunpaman, kapag magkasamang may UITapGestureRecognizer sa parehong view, maaaring kailanganin ang require(toFail:) upang maiwasan ang maling pagkilala ng tap.
Sa Android, ang pangunahing API para sa pagkilala ng swipe ay GestureDetector na may callback na OnGestureListener, partikular ang paraang onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY). Sinusuri ng GestureDetector ang simula at huling posisyon ng daliri, bilis ng paggalaw sa mga axis at distansya, pagkatapos ay tinatawag ang onFling kapag lumampas sa mga threshold.
Ang mga minimum na threshold ay naka-configure sa pamamagitan ng ViewConfiguration: VelocityTracker.getMinVelocity() (~100 px/s) at ViewConfiguration.getScaledTouchSlop() (~8–16 dp). Ang custom na OnSwipeTouchListener ay isang pangkaraniwang pattern na nagpapasimple sa API: hindi kailangang manu-manong kalkulahin ng developer ang direksyon at bilis. Ang Android Support Library ay hindi naglalaman ng built-in na „SwipeDetector”, kaya ang custom na wrapper ay ang karaniwang solusyon.
Para sa swipe sa mga listahan, inirerekomenda ng Google ang paggamit ng ItemTouchHelper.SimpleCallback mula sa RecyclerView, na nag-aabstrak ng detection ng kilos, animation at mga callback na onSwiped(). Sa IT Sectr gumagamit kami ng custom na SwipeListener para sa ViewPager2 at card interface — nagbibigay ito ng kontrol sa sensitivity ng swipe nang hindi sinasakripisyo ang performance.
Para sa mga listahan (UITableView, RecyclerView) ang Apple at Google ay nagbibigay ng mga espesyalisadong API na pumapalit sa manual na pagdagdag ng UISwipeGestureRecognizer. Ang mga API na ito ay sumusuporta sa mga action button, custom na animation at mga kilos na „swipe para tanggalin” — karaniwang pattern ng mobile apps.
Sa iOS (11+) ginagamit ang UISwipeActionsConfiguration: ang paraang tableView(_:leadingSwipeActionsConfigurationForRowAt:) ay nagbabalik ng array ng UIContextualAction — mga button na may pamagat, istilo (destructive, normal) at handler. Halimbawa, „Tanggalin” — .destructive na may pulang background, „Archive” — .normal na may kulay abo. Ang system mismo ang nag-a-animate ng paglitaw ng mga button at tumatawag ng completion block pagkatapos pindutin.
Sa Android, ang ItemTouchHelper.SimpleCallback ay ikinakabit sa RecyclerView sa pamamagitan ng ItemTouchHelper.attachToRecyclerView(). Mga parameter — flag ng direksyon (start, end, up, down) at callback na onSwiped(viewHolder, direction). Sa loob ng onSwiped, tinatawag ang adapter.notifyItemRemoved(position) para tanggalin ang elemento na may animation. Awtomatikong pinangangasiwaan ng ItemTouchHelper ang mga kilos, conflict sa scroll at pagbabalik ng elemento kung hindi natapos ang swipe. Ayon sa Google I/O 2024, ang ItemTouchHelper ay ginagamit sa 70% ng Android apps na may swipe actions sa mga listahan.
Nagdaragdag ng UISwipeGestureRecognizer sa view para bumalik sa nakaraang screen. Ipinapakita ng code ang minimum na configuration ng tagakilala na may direksyong .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)
}
}
}
Ang tagakilala ay ikinakabit sa root-view ng controller. Ang pagsusuri ng navigationController.viewControllers.count ay ginagarantiyahan na ang pop ay ginagawa lamang kung may nakaraang screen sa stack. Para sa modal controllers, ginagamit ang dismiss. Ang code ay hindi nangangailangan ng state check — ang UISwipeGestureRecognizer ay diskreto at tumatawag ng action lamang sa matagumpay na pagkilala.
Nagpapatupad ng simpleng wrapper ng GestureDetector na tumutukoy sa direksyon ng swipe at tumatawag ng mga callback na 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() {}
}
Pinapalawak ng OnSwipeTouchListener ang SimpleOnGestureListener, ipinapatupad ang onFling. Tinutukoy ng diffX/diffY ang direksyon, SWIPE_THRESHOLD (100px) at SWIPE_VELOCITY_THRESHOLD (100 px/s) — mga threshold. Paggamit: view.setOnTouchListener(OnSwipeTouchListener(context).apply { onSwipeLeft = { dismiss() } }).
Nagdaragdag ng delete button kapag nag-swipe pakaliwa sa cell ng table. Gumagamit ng built-in na API ng iOS 11+ nang walang manual na pagkilala ng kilos.
func tableView(
_ tableView: UITableView,
trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath
) -> UISwipeActionsConfiguration? {
let deleteAction = UIContextualAction(
style: .destructive,
title: "Tanggalin"
) { _, _, 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
}
Ang pamamaraan ay nagbabalik ng UISwipeActionsConfiguration na may array ng UIContextualAction. style: .destructive ay awtomatikong nagtatakda ng pulang background. Ang performsFirstActionWithFullSwipe = true ay nagpapahintulot na gawin ang aksyon na may buong swipe nang walang karagdagang pagpindot. Sa IT Sectr ginagamit namin ang API na ito para sa lahat ng listahan na may aksyon — ito ay standardized, sumusuporta sa VoiceOver at hindi nangangailangan ng custom na GestureRecognizer.
Mga madalas itanong
Swipe — diskretong kilos na may mabilis na paggalaw at pag-angat ng daliri, pan — tuloy-tuloy na pag-drag na may pagsubaybay ng coordinate. Ang UISwipeGestureRecognizer ay nag-a-activate nang isang beses, ang UIPanGestureRecognizer ay bumubuo ng .began → .changed → .ended. Ang pagpili ay depende sa scenario: swipe — para sa mga aksyon (tanggalin, ibalik), pan — para sa paglipat (mapa, slider).
Ang lohika ng kilos ay magkapareho, ngunit ang API ay naiiba. Gumagamit ang iOS ng UISwipeGestureRecognizer na may direction. Gumagamit ang Android ng GestureDetector.onFling() na may custom na threshold. Ang resulta — parehong UX na may ibang implementasyon. Ang cross-platform frameworks (Flutter, React Native) ay nag-aabstrak ng pagkakaiba sa pamamagitan ng pinag-isang API ng swipe.
Sa iOS (11+) gamitin ang UISwipeActionsConfiguration sa UITableViewDelegate. Sa Android — ItemTouchHelper.SimpleCallback para sa RecyclerView. Pinapalitan ng mga API na ito ang manual na GestureRecognizer, sumusuporta sa mga action button at animation, wastong pinangangasiwaan ang conflict sa scroll at umaangkop sa platform HIG.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.