মূল বিষয়
সোয়াইপ হল স্ক্রিন পৃষ্ঠে আঙুলের একটি দ্রুত স্লাইডিং গতি যা উঠিয়ে নেওয়ার মাধ্যমে শেষ হয়। সোয়াইপ ছোট হতে পারে (একটি উপাদান ফ্লিপ করা) বা লম্বা (পর্দা খোলা), তবে মূল বৈশিষ্ট্য হল ডিসক্রিটনেস: সিস্টেম এটিকে একটি একক ইভেন্ট হিসাবে স্বীকৃতি দেয়, ক্রমাগত স্থানাঙ্কের ক্রম হিসাবে নয়।
মোবাইল OS তিনটি প্যারামিটারের ভিত্তিতে সোয়াইপ শনাক্ত করে: ন্যূনতম দূরত্ব (সীমা), ন্যূনতম গতি (velocity), এবং দিক। যদি আঙুল ধীরে চলে বা দূরত্ব অপর্যাপ্ত হয়, সিস্টেম জেসচারটিকে প্যানিং বা ট্যাপ হিসাবে ব্যাখ্যা করে। প্ল্যাটফর্মের মধ্যে সীমা মান ভিন্ন: iOS একটি নির্দিষ্ট সীমাসহ UISwipeGestureRecognizer এ একটি ধ্রুবক ব্যবহার করে, Android ViewConfiguration.getScaledTouchSlop() ব্যবহার করে যা স্ক্রিন ঘনত্বের উপর নির্ভর করে ~8–16 dp ফেরত দেয়।
Android Developers Documentation অনুসারে, GestureDetector এ onFling (সোয়াইপ) 100 px/s এর উপরে গতি এবং 50px থেকে দূরত্বে সক্রিয় হয়। IT Sectr এ, আমরা নেভিগেশন (গ্যালারি, কার্ড ইন্টারফেস, অনবোর্ডিং) এর জন্য সোয়াইপ ব্যবহার করি — এই জেসচারটি সব বয়সের ব্যবহারকারীদের জন্য স্বজ্ঞাত।
সোয়াইপ এবং প্যানিং (pan/drag) বিভিন্ন ধরণের জেসচার, যদিও উভয়েই স্ক্রিনে আঙুল সরানো জড়িত। সোয়াইপ ডিসক্রিট এবং এর অর্থ "একটি ক্রিয়া সম্পাদন করা," যখন প্যানিং ক্রমাগত এবং এর অর্থ "একটি বস্তু সরানো যতক্ষণ আঙুল স্ক্রিনে থাকে।"
| প্যারামিটার | সোয়াইপ (Swipe) | প্যান/ড্র্যাগ (Pan/Drag) |
|---|---|---|
| ধরন | ডিসক্রিট | ক্রমাগত |
| ইভেন্ট | একক (শনাক্ত/শনাক্ত নয়) | একাধিক (.began → .changed → .ended) |
| গতি | উচ্চ (দ্রুত গতি) | যেকোনো (ধীর গতি) |
| iOS উদাহরণ | UISwipeGestureRecognizer | UIPanGestureRecognizer |
| Android উদাহরণ | GestureDetector.onFling() | GestureDetector.onScroll() |
| পরিস্থিতি | ইমেল মুছে ফেলা, পৃষ্ঠা উল্টানো | মানচিত্র সরানো, ফাইল টেনে আনা |
| স্থানাঙ্ক ট্র্যাকিং | না (শুধু দিক) | হ্যাঁ (ক্রমাগত স্থানাঙ্ক আপডেট) |
সোয়াইপ এবং প্যানিংয়ের মধ্যে পছন্দ কাজের উপর নির্ভর করে। একটি উপাদানের ক্রিয়ার জন্য (মুছে ফেলা, আর্কাইভ করা, মেনু খোলা) সোয়াইপ ব্যবহার করুন। প্রত্যক্ষ হেরফের (সরানো, স্কেল করা) জন্য প্যানিং ব্যবহার করুন। একই উপাদানে জেসচার মিশ্রিত করতে require(toFail:) বা কাস্টম লজিক প্রয়োজন।
UISwipeGestureRecognizer হল UIGestureRecognizer এর একটি উপশ্রেণী যা চারটি দিকের একটিতে ডিসক্রিট সোয়াইপ শনাক্ত করে। UIPanGestureRecognizer এর বিপরীতে, এটি মধ্যবর্তী .changed ইভেন্ট তৈরি করে না: শনাক্তকরণের পর, ক্রিয়াটি ঠিক একবার কল করা হয়।
direction প্রপার্টি (UISwipeGestureRecognizer.Direction) ট্র্যাক করা দিক নির্ধারণ করে — .left, .right, .up, .down। মাস্কের মাধ্যমে দিকগুলি একত্রিত করা যেতে পারে: অনুভূমিক সোয়াইপের জন্য [.left, .right]। numberOfTouchesRequired প্রপার্টি আঙুলের সংখ্যা নির্ধারণ করে — ডিফল্ট 1। UISwipeGestureRecognizer এর কনফিগারযোগ্য দূরত্ব সীমা নেই — iOS প্রায় 20px এর একটি বিল্ট-ইন মান ব্যবহার করে, যা নির্ভরযোগ্য শনাক্তকরণের জন্য যথেষ্ট।
যেহেতু UISwipeGestureRecognizer একটি ডিসক্রিট শনাক্তকারী, এটি UIPanGestureRecognizer এর সাথে বিরোধ করে না: ধীর গতি pan ট্রিগার করে, দ্রুত গতি swipe ট্রিগার করে। তবে, একই ভিউতে UITapGestureRecognizer এর সাথে সহাবস্থানে, ভুল ট্যাপ শনাক্তকরণ প্রতিরোধের জন্য require(toFail:) প্রয়োজন হতে পারে।
Android এ, সোয়াইপ শনাক্তকরণের জন্য প্রাথমিক API হল GestureDetector যার সাথে OnGestureListener কলব্যাক, বিশেষ করে onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) মেথড। GestureDetector প্রাথমিক এবং চূড়ান্ত আঙুলের অবস্থান, অক্ষ বরাবর গতির গতি এবং দূরত্ব বিশ্লেষণ করে এবং সীমা অতিক্রম করলে onFling কল করে।
ন্যূনতম সীমা ViewConfiguration এর মাধ্যমে কনফিগার করা হয়: VelocityTracker.getMinVelocity() (~100 px/s) এবং ViewConfiguration.getScaledTouchSlop() (~8–16 dp)। একটি কাস্টম OnSwipeTouchListener একটি সাধারণ প্যাটার্ন যা API সরলীকৃত করে: ডেভেলপারকে ম্যানুয়ালি দিক এবং গতি গণনা করতে হয় না। Android Support Library তে বিল্ট-ইন "SwipeDetector" অন্তর্ভুক্ত নয়, তাই কাস্টম র্যাপার হল আদর্শ সমাধান।
তালিকায় সোয়াইপের জন্য, Google RecyclerView থেকে ItemTouchHelper.SimpleCallback ব্যবহার করার পরামর্শ দেয়, যা জেসচার শনাক্তকরণ, অ্যানিমেশন এবং onSwiped() কলব্যাককে অ্যাবস্ট্রাক্ট করে। IT Sectr এ, আমরা ViewPager2 এবং কার্ড ইন্টারফেসের জন্য কাস্টম SwipeListener ব্যবহার করি — এটি পারফরম্যান্স বিসর্জন না দিয়ে সোয়াইপ সংবেদনশীলতার উপর নিয়ন্ত্রণ দেয়।
তালিকার জন্য (UITableView, RecyclerView), Apple এবং Google বিশেষায়িত API প্রদান করে যা ম্যানুয়ালি UISwipeGestureRecognizer যোগ করার পরিবর্তে ব্যবহার করা হয়। এই APIগুলি অ্যাকশন বাটন, কাস্টম অ্যানিমেশন এবং "সোয়াইপ টু ডিলিট" জেসচার সমর্থন করে — মোবাইল অ্যাপ্লিকেশনের মানক প্যাটার্ন।
iOS (11+) এ, UISwipeActionsConfiguration ব্যবহার করা হয়: tableView(_:leadingSwipeActionsConfigurationForRowAt:) মেথড UIContextualAction এর একটি অ্যারে ফেরত দেয় — শিরোনাম, স্টাইল (destructive, normal) এবং হ্যান্ডলার সহ বাটন। উদাহরণস্বরূপ, "মুছুন" — লাল ব্যাকগ্রাউন্ড সহ .destructive, "আর্কাইভ" — ধূসর ব্যাকগ্রাউন্ড সহ .normal। সিস্টেম বাটনগুলির উপস্থিতি অ্যানিমেট করে এবং ট্যাপের পরে completion ব্লক কল করে।
Android এ, ItemTouchHelper.SimpleCallback ItemTouchHelper.attachToRecyclerView() এর মাধ্যমে RecyclerView এর সাথে সংযুক্ত করা হয়। প্যারামিটারগুলির মধ্যে দিক ফ্ল্যাগ (start, end, up, down) এবং onSwiped(viewHolder, direction) কলব্যাক অন্তর্ভুক্ত। onSwiped এর ভিতরে, অ্যানিমেশন সহ আইটেম সরাতে adapter.notifyItemRemoved(position) কল করা হয়। ItemTouchHelper স্বয়ংক্রিয়ভাবে জেসচার, স্ক্রোল বিরোধ এবং আইটেম ফিরিয়ে আনা হ্যান্ডল করে যদি সোয়াইপ সম্পূর্ণ না হয়। Google I/O 2024 অনুসারে, তালিকায় সোয়াইপ অ্যাকশন সহ 70% Android অ্যাপ্লিকেশনে ItemTouchHelper ব্যবহৃত হয়।
পূর্ববর্তী স্ক্রিনে ফিরে আসার জন্য ভিউতে UISwipeGestureRecognizer যোগ করে। কোডটি .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)
}
}
}
শনাক্তকারী কন্ট্রোলারের রুট-ভিউতে সংযুক্ত থাকে। navigationController.viewControllers.count চেক নিশ্চিত করে যে pop কেবল তখনই সম্পাদিত হয় যখন স্ট্যাকে পূর্ববর্তী স্ক্রিন থাকে। মোডাল কন্ট্রোলারের জন্য, dismiss ব্যবহার করা হয়। কোডের অবস্থা পরীক্ষার প্রয়োজন নেই — UISwipeGestureRecognizer ডিসক্রিট এবং শুধুমাত্র সফল শনাক্তকরণে ক্রিয়া কল করে।
একটি সরল GestureDetector র্যাপার প্রয়োগ করে যা সোয়াইপ দিক নির্ধারণ করে এবং 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 onFling বাস্তবায়ন করে SimpleOnGestureListener কে প্রসারিত করে। diffX/diffY দিক নির্ধারণ করে, SWIPE_THRESHOLD (100px) এবং SWIPE_VELOCITY_THRESHOLD (100 px/s) সীমা। ব্যবহার: view.setOnTouchListener(OnSwipeTouchListener(context).apply { onSwipeLeft = { dismiss() } }).
টেবিল সেলে বামে সোয়াইপ করার সময় একটি মুছে ফেলা বাটন যোগ করে। ম্যানুয়াল জেসচার শনাক্তকরণ ছাড়া বিল্ট-ইন iOS 11+ API ব্যবহার করে।
func tableView(
_ tableView: UITableView,
trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath
) -> UISwipeActionsConfiguration? {
let deleteAction = UIContextualAction(
style: .destructive,
title: "মুছুন"
) { _, _, 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
}
মেথডটি UIContextualAction এর একটি অ্যারে সহ UISwipeActionsConfiguration ফেরত দেয়। style: .destructive স্বয়ংক্রিয়ভাবে লাল ব্যাকগ্রাউন্ড নির্ধারণ করে। performsFirstActionWithFullSwipe = true অতিরিক্ত ট্যাপ ছাড়া সম্পূর্ণ সোয়াইপের মাধ্যমে ক্রিয়া সম্পাদনের অনুমতি দেয়। IT Sectr এ, আমরা অ্যাকশন সহ সমস্ত তালিকার জন্য এই API ব্যবহার করি — এটি মানকীকৃত, VoiceOver সমর্থন করে এবং কাস্টম GestureRecognizer প্রয়োজন হয় না।
সচরাচর জিজ্ঞাসিত প্রশ্ন
সোয়াইপ একটি ডিসক্রিট জেসচার দ্রুত গতি এবং আঙুল তোলা সহ, প্যানিং হল স্থানাঙ্ক ট্র্যাকিং সহ ক্রমাগত টেনে আনা। UISwipeGestureRecognizer একবার সক্রিয় হয়, UIPanGestureRecognizer .began → .changed → .ended তৈরি করে। পছন্দ পরিস্থিতির উপর নির্ভর করে: সোয়াইপ ক্রিয়ার জন্য (মুছে ফেলা, উল্টানো), pan গতির জন্য (মানচিত্র, স্লাইডার)।
জেসচার লজিক একই, কিন্তু API ভিন্ন। iOS UISwipeGestureRecognizer ব্যবহার করে direction সহ। Android কাস্টম সীমা সহ GestureDetector.onFling() ব্যবহার করে। ফলাফল ভিন্ন বাস্তবায়নে একই UX। ক্রস-প্ল্যাটফর্ম ফ্রেমওয়ার্ক (Flutter, React Native) একটি ইউনিফাইড সোয়াইপ API এর মাধ্যমে পার্থক্য অ্যাবস্ট্রাক্ট করে।
iOS (11+) এ, UITableViewDelegate এ UISwipeActionsConfiguration ব্যবহার করুন। Android এ, RecyclerView এর জন্য ItemTouchHelper.SimpleCallback ব্যবহার করুন। এই APIগুলি ম্যানুয়াল GestureRecognizer প্রতিস্থাপন করে, অ্যাকশন বাটন এবং অ্যানিমেশন সমর্থন করে, স্ক্রোল বিরোধ সঠিকভাবে হ্যান্ডল করে এবং প্ল্যাটফর্ম HIG এর সাথে খাপ খায়।
সারাংশ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন