যখন কোনো ব্যবহারকারী টাচস্ক্রিনে এক বা একাধিক আঙুল রাখেন এবং আপনার অ্যাপ স্পর্শের এই ধরণটিকে একটি অঙ্গভঙ্গি হিসেবে শনাক্ত করে, তখন একটি টাচ জেসচার ঘটে। জেসচার শনাক্তকরণের দুটি পর্যায় রয়েছে:
- স্পর্শ ইভেন্টের ডেটা সংগ্রহ করা হচ্ছে।
- আপনার অ্যাপ যে অঙ্গভঙ্গিগুলো সমর্থন করে, ডেটাটি সেগুলোর মানদণ্ড পূরণ করে কিনা তা নির্ধারণ করতে ডেটা বিশ্লেষণ করা।
অ্যান্ড্রয়েডএক্স ক্লাস
এই ডকুমেন্টের উদাহরণগুলিতে GestureDetectorCompat এবং MotionEventCompat ক্লাস ব্যবহার করা হয়েছে। এই ক্লাসগুলি AndroidX লাইব্রেরিতে রয়েছে। পূর্ববর্তী ডিভাইসগুলির সাথে সামঞ্জস্যতা বজায় রাখতে যেখানে সম্ভব AndroidX ক্লাস ব্যবহার করুন। MotionEventCompat MotionEvent ক্লাসের বিকল্প নয় । বরং, এটি কিছু স্ট্যাটিক ইউটিলিটি মেথড প্রদান করে, যেগুলিতে আপনি আপনার MotionEvent অবজেক্টটি পাস করে সেই ইভেন্টের সাথে সম্পর্কিত অ্যাকশনটি গ্রহণ করতে পারেন।
তথ্য সংগ্রহ করুন
যখন কোনো ব্যবহারকারী স্ক্রিনে এক বা একাধিক আঙুল রাখেন, তখন টাচ ইভেন্ট গ্রহণকারী ভিউ-এর onTouchEvent() কলব্যাকটি ট্রিগার হয়। প্রতিটি টাচ ইভেন্টের ক্রম—যেমন অবস্থান, চাপ, আকার এবং আরেকটি আঙুল যোগ করা—যা একটি জেসচার হিসেবে চিহ্নিত হয়, তার জন্য onTouchEvent() একাধিকবার ফায়ার হয়।
ব্যবহারকারী যখন প্রথমবার স্ক্রিনে স্পর্শ করেন, তখন এই জেসচারটি শুরু হয়; সিস্টেম যখন ব্যবহারকারীর আঙুল বা আঙুলগুলোর অবস্থান ট্র্যাক করতে থাকে, তখন এটি চলতে থাকে; এবং ব্যবহারকারীর শেষ আঙুলটি স্ক্রিন থেকে সরে যাওয়ার চূড়ান্ত ইভেন্টটি ক্যাপচার করার মাধ্যমে এটি শেষ হয়। এই পুরো ইন্টারঅ্যাকশন জুড়ে, onTouchEvent() -এ পাঠানো MotionEvent প্রতিটি ইন্টারঅ্যাকশনের বিস্তারিত তথ্য প্রদান করে। আপনার অ্যাপ তার প্রয়োজনীয় কোনো জেসচার ঘটবে কি না, তা নির্ধারণ করতে MotionEvent দ্বারা প্রদত্ত ডেটা ব্যবহার করতে পারে।
একটি অ্যাক্টিভিটি বা ভিউ-এর জন্য টাচ ইভেন্ট ক্যাপচার করুন।
কোনো Activity বা View তে টাচ ইভেন্ট ইন্টারসেপ্ট করতে, onTouchEvent() কলব্যাকটি ওভাররাইড করুন।
নিম্নলিখিত কোড স্নিপেটটি event প্যারামিটার থেকে ব্যবহারকারীর করা কাজটি বের করতে getAction() ব্যবহার করে। এটি আপনাকে সেই মূল ডেটা দেয় যা আপনার কাঙ্ক্ষিত কোনো অঙ্গভঙ্গি ঘটেছে কিনা তা নির্ধারণ করতে প্রয়োজন।
কোটলিন
class MainActivity : Activity() { ... // This example shows an Activity. You can use the same approach if you are // subclassing a View. override fun onTouchEvent(event: MotionEvent): Boolean { return when (event.action) { MotionEvent.ACTION_DOWN -> { Log.d(DEBUG_TAG, "Action was DOWN") true } MotionEvent.ACTION_MOVE -> { Log.d(DEBUG_TAG, "Action was MOVE") true } MotionEvent.ACTION_UP -> { Log.d(DEBUG_TAG, "Action was UP") true } MotionEvent.ACTION_CANCEL -> { Log.d(DEBUG_TAG, "Action was CANCEL") true } MotionEvent.ACTION_OUTSIDE -> { Log.d(DEBUG_TAG, "Movement occurred outside bounds of current screen element") true } else -> super.onTouchEvent(event) } } }
জাভা
public class MainActivity extends Activity { ... // This example shows an Activity. You can use the same approach if you are // subclassing a View. @Override public boolean onTouchEvent(MotionEvent event){ switch(event.getAction()) { case (MotionEvent.ACTION_DOWN) : Log.d(DEBUG_TAG,"Action was DOWN"); return true; case (MotionEvent.ACTION_MOVE) : Log.d(DEBUG_TAG,"Action was MOVE"); return true; case (MotionEvent.ACTION_UP) : Log.d(DEBUG_TAG,"Action was UP"); return true; case (MotionEvent.ACTION_CANCEL) : Log.d(DEBUG_TAG,"Action was CANCEL"); return true; case (MotionEvent.ACTION_OUTSIDE) : Log.d(DEBUG_TAG,"Movement occurred outside bounds of current screen element"); return true; default : return super.onTouchEvent(event); } }
ব্যবহারকারী যখন ট্যাপ, টাচ ও হোল্ড এবং ড্র্যাগ করেন, তখন এই কোডটি Logcat-এ নিম্নলিখিতের মতো বার্তা তৈরি করে:
GESTURES D Action was DOWN GESTURES D Action was UP GESTURES D Action was MOVE
কাস্টম জেসচারের ক্ষেত্রে, এই ইভেন্টগুলো আপনার হ্যান্ডেল করার মতো কোনো জেসচারকে নির্দেশ করে কিনা তা নির্ধারণ করতে আপনি সেগুলোর উপর নিজের মতো করে প্রসেসিং করতে পারেন। তবে, যদি আপনার অ্যাপে ডাবল-ট্যাপ, টাচ অ্যান্ড হোল্ড, ফ্লিং ইত্যাদির মতো সাধারণ জেসচার ব্যবহৃত হয়, তাহলে আপনি GestureDetector ক্লাসটির সুবিধা নিতে পারেন। GestureDetector প্রতিটি টাচ ইভেন্টকে আলাদাভাবে প্রসেস না করেই সাধারণ জেসচারগুলো শনাক্ত করা আপনার জন্য সহজ করে তোলে। এই বিষয়টি ‘Detect gestures’ অংশে আরও বিস্তারিত আলোচনা করা হয়েছে।
একটিমাত্র ভিউয়ের জন্য টাচ ইভেন্ট ক্যাপচার করুন
onTouchEvent() এর বিকল্প হিসেবে, আপনি setOnTouchListener() মেথড ব্যবহার করে যেকোনো View অবজেক্টের সাথে একটি View.OnTouchListener অবজেক্ট সংযুক্ত করতে পারেন। এর ফলে, বিদ্যমান কোনো View সাবক্লাস না করেই টাচ ইভেন্ট শোনা সম্ভব হয়, যেমনটি নিচের উদাহরণে দেখানো হয়েছে:
কোটলিন
findViewById<View>(R.id.my_view).setOnTouchListener { v, event -> // Respond to touch events. true }
জাভা
View myView = findViewById(R.id.my_view); myView.setOnTouchListener(new OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { // Respond to touch events. return true; } });
ACTION_DOWN ইভেন্টের জন্য false রিটার্ন করে এমন কোনো লিসেনার তৈরি করার ব্যাপারে সতর্ক থাকুন। যদি আপনি এমনটা করেন, তাহলে পরবর্তী ACTION_MOVE এবং ACTION_UP ইভেন্টগুলোর জন্য লিসেনারটি কল করা হয় না। এর কারণ হলো, ACTION_DOWN হলো সমস্ত টাচ ইভেন্টের সূচনা বিন্দু।
আপনি যদি একটি কাস্টম ভিউ তৈরি করেন, তাহলে পূর্বে বর্ণিত পদ্ধতি অনুযায়ী onTouchEvent() ওভাররাইড করতে পারেন।
অঙ্গভঙ্গি সনাক্ত করুন
অ্যান্ড্রয়েড সাধারণ জেসচার শনাক্ত করার জন্য GestureDetector ক্লাসটি প্রদান করে। এটি যেসব জেসচার সমর্থন করে তার মধ্যে কয়েকটি হলো onDown() , onLongPress() , এবং onFling() । আপনি পূর্বে বর্ণিত onTouchEvent() মেথডের সাথে একত্রে GestureDetector ব্যবহার করতে পারেন।
সমস্ত সমর্থিত অঙ্গভঙ্গি সনাক্ত করুন
যখন আপনি একটি GestureDetectorCompat অবজেক্ট ইনস্ট্যানশিয়েট করেন, তখন এটি যে প্যারামিটারগুলো গ্রহণ করে তার মধ্যে একটি হলো এমন একটি ক্লাস যা GestureDetector.OnGestureListener ইন্টারফেসটি ইমপ্লিমেন্ট করে। কোনো নির্দিষ্ট টাচ ইভেন্ট ঘটলে GestureDetector.OnGestureListener ব্যবহারকারীদের অবহিত করে। আপনার GestureDetector অবজেক্ট যাতে ইভেন্ট গ্রহণ করতে পারে, তা নিশ্চিত করতে ভিউ বা অ্যাক্টিভিটির onTouchEvent() মেথডটি ওভাররাইড করুন এবং পর্যবেক্ষণ করা সমস্ত ইভেন্ট ডিটেক্টর ইনস্ট্যান্সটিতে পাঠিয়ে দিন।
নিম্নলিখিত কোড অংশে, প্রতিটি on <TouchEvent> মেথডের রিটার্ন ভ্যালু ' true হলে বোঝা যায় যে টাচ ইভেন্টটি হ্যান্ডেল করা হয়েছে। অন্যদিকে, false ' রিটার্ন ভ্যালু টাচটি সফলভাবে হ্যান্ডেল না হওয়া পর্যন্ত ইভেন্টগুলোকে ভিউ স্ট্যাকের নিচের দিকে পাঠাতে থাকে।
যদি আপনি একটি টেস্ট অ্যাপে নিম্নলিখিত কোড স্নিপেটটি চালান, তাহলে টাচ স্ক্রিনের সাথে ইন্টারঅ্যাক্ট করার সময় কীভাবে অ্যাকশনগুলো ট্রিগার হয় এবং প্রতিটি টাচ ইভেন্টের জন্য MotionEvent এর বিষয়বস্তু কী, সে সম্পর্কে একটি ধারণা পেতে পারেন। এরপর আপনি দেখতে পাবেন যে সাধারণ ইন্টারঅ্যাকশনের জন্য কী পরিমাণ ডেটা তৈরি হচ্ছে।
কোটলিন
private const val DEBUG_TAG = "Gestures" class MainActivity : Activity(), GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener { private lateinit var mDetector: GestureDetectorCompat // Called when the activity is first created. public override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // Instantiate the gesture detector with the // application context and an implementation of // GestureDetector.OnGestureListener. mDetector = GestureDetectorCompat(this, this) // Set the gesture detector as the double-tap // listener. mDetector.setOnDoubleTapListener(this) } override fun onTouchEvent(event: MotionEvent): Boolean { return if (mDetector.onTouchEvent(event)) { true } else { super.onTouchEvent(event) } } override fun onDown(event: MotionEvent): Boolean { Log.d(DEBUG_TAG, "onDown: $event") return true } override fun onFling( event1: MotionEvent, event2: MotionEvent, velocityX: Float, velocityY: Float ): Boolean { Log.d(DEBUG_TAG, "onFling: $event1 $event2") return true } override fun onLongPress(event: MotionEvent) { Log.d(DEBUG_TAG, "onLongPress: $event") } override fun onScroll( event1: MotionEvent, event2: MotionEvent, distanceX: Float, distanceY: Float ): Boolean { Log.d(DEBUG_TAG, "onScroll: $event1 $event2") return true } override fun onShowPress(event: MotionEvent) { Log.d(DEBUG_TAG, "onShowPress: $event") } override fun onSingleTapUp(event: MotionEvent): Boolean { Log.d(DEBUG_TAG, "onSingleTapUp: $event") return true } override fun onDoubleTap(event: MotionEvent): Boolean { Log.d(DEBUG_TAG, "onDoubleTap: $event") return true } override fun onDoubleTapEvent(event: MotionEvent): Boolean { Log.d(DEBUG_TAG, "onDoubleTapEvent: $event") return true } override fun onSingleTapConfirmed(event: MotionEvent): Boolean { Log.d(DEBUG_TAG, "onSingleTapConfirmed: $event") return true } }
জাভা
public class MainActivity extends Activity implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener{ private static final String DEBUG_TAG = "Gestures"; private GestureDetectorCompat mDetector; // Called when the activity is first created. @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Instantiate the gesture detector with the // application context and an implementation of // GestureDetector.OnGestureListener. mDetector = new GestureDetectorCompat(this,this); // Set the gesture detector as the double-tap // listener. mDetector.setOnDoubleTapListener(this); } @Override public boolean onTouchEvent(MotionEvent event){ if (this.mDetector.onTouchEvent(event)) { return true; } return super.onTouchEvent(event); } @Override public boolean onDown(MotionEvent event) { Log.d(DEBUG_TAG,"onDown: " + event.toString()); return true; } @Override public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) { Log.d(DEBUG_TAG, "onFling: " + event1.toString() + event2.toString()); return true; } @Override public void onLongPress(MotionEvent event) { Log.d(DEBUG_TAG, "onLongPress: " + event.toString()); } @Override public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX, float distanceY) { Log.d(DEBUG_TAG, "onScroll: " + event1.toString() + event2.toString()); return true; } @Override public void onShowPress(MotionEvent event) { Log.d(DEBUG_TAG, "onShowPress: " + event.toString()); } @Override public boolean onSingleTapUp(MotionEvent event) { Log.d(DEBUG_TAG, "onSingleTapUp: " + event.toString()); return true; } @Override public boolean onDoubleTap(MotionEvent event) { Log.d(DEBUG_TAG, "onDoubleTap: " + event.toString()); return true; } @Override public boolean onDoubleTapEvent(MotionEvent event) { Log.d(DEBUG_TAG, "onDoubleTapEvent: " + event.toString()); return true; } @Override public boolean onSingleTapConfirmed(MotionEvent event) { Log.d(DEBUG_TAG, "onSingleTapConfirmed: " + event.toString()); return true; } }
সমর্থিত অঙ্গভঙ্গির একটি উপসেট সনাক্ত করুন
যদি আপনি কেবল কয়েকটি জেসচার প্রসেস করতে চান, তাহলে GestureDetector.OnGestureListener ইন্টারফেসটি ইমপ্লিমেন্ট করার পরিবর্তে GestureDetector.SimpleOnGestureListener এক্সটেন্ড করতে পারেন।
GestureDetector.SimpleOnGestureListener on <TouchEvent> সমস্ত মেথডের জন্য false রিটার্ন করার মাধ্যমে সেগুলোর একটি ইমপ্লিমেন্টেশন প্রদান করে। এটি আপনাকে শুধুমাত্র আপনার প্রয়োজনীয় মেথডগুলো ওভাররাইড করার সুযোগ দেয়। উদাহরণস্বরূপ, নিচের কোড স্নিপেটটি এমন একটি ক্লাস তৈরি করে যা GestureDetector.SimpleOnGestureListener এক্সটেন্ড করে এবং onFling() ও onDown() মেথড দুটিকে ওভাররাইড করে।
আপনি GestureDetector.OnGestureListener বা GestureDetector.SimpleOnGestureListener যা-ই ব্যবহার করুন না কেন, একটি onDown() মেথড ইমপ্লিমেন্ট করা উত্তম অভ্যাস যা true রিটার্ন করে। এর কারণ হলো, সমস্ত জেসচার একটি onDown() মেসেজ দিয়ে শুরু হয়। আপনি যদি onDown() থেকে false রিটার্ন করেন, যেমনটা GestureDetector.SimpleOnGestureListener ডিফল্টভাবে করে থাকে, তাহলে সিস্টেম ধরে নেয় যে আপনি জেসচারের বাকি অংশ উপেক্ষা করতে চান, এবং GestureDetector.OnGestureListener এর অন্যান্য মেথডগুলো কল করা হয় না। এটি আপনার অ্যাপে অপ্রত্যাশিত সমস্যা সৃষ্টি করতে পারে। শুধুমাত্র তখনই onDown() থেকে false রিটার্ন করুন, যখন আপনি সত্যিই একটি সম্পূর্ণ জেসচার উপেক্ষা করতে চান।
কোটলিন
private const val DEBUG_TAG = "Gestures" class MainActivity : Activity() { private lateinit var mDetector: GestureDetectorCompat public override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) mDetector = GestureDetectorCompat(this, MyGestureListener()) } override fun onTouchEvent(event: MotionEvent): Boolean { mDetector.onTouchEvent(event) return super.onTouchEvent(event) } private class MyGestureListener : GestureDetector.SimpleOnGestureListener() { override fun onDown(event: MotionEvent): Boolean { Log.d(DEBUG_TAG, "onDown: $event") return true } override fun onFling( event1: MotionEvent, event2: MotionEvent, velocityX: Float, velocityY: Float ): Boolean { Log.d(DEBUG_TAG, "onFling: $event1 $event2") return true } } }
জাভা
public class MainActivity extends Activity { private GestureDetectorCompat mDetector; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mDetector = new GestureDetectorCompat(this, new MyGestureListener()); } @Override public boolean onTouchEvent(MotionEvent event){ if (this.mDetector.onTouchEvent(event)) { return true; } return super.onTouchEvent(event); } class MyGestureListener extends GestureDetector.SimpleOnGestureListener { private static final String DEBUG_TAG = "Gestures"; @Override public boolean onDown(MotionEvent event) { Log.d(DEBUG_TAG,"onDown: " + event.toString()); return true; } @Override public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) { Log.d(DEBUG_TAG, "onFling: " + event1.toString() + event2.toString()); return true; } } }
