এই পাঠে টাচ ইভেন্টের মাধ্যমে নড়াচড়া ট্র্যাক করার পদ্ধতি বর্ণনা করা হয়েছে।
যখনই বর্তমান টাচ কন্ট্যাক্টের অবস্থান, চাপ বা আকার পরিবর্তিত হয়, তখন একটি ACTION_MOVE ইভেন্ট সহ একটি নতুন onTouchEvent() ট্রিগার হয়। "সাধারণ অঙ্গভঙ্গি সনাক্ত করুন" অংশে যেমন বর্ণনা করা হয়েছে, এই সমস্ত ইভেন্ট onTouchEvent() এর MotionEvent প্যারামিটারে রেকর্ড করা হয়।
যেহেতু আঙুল-ভিত্তিক স্পর্শ সবসময় মিথস্ক্রিয়ার সবচেয়ে নির্ভুল মাধ্যম নয়, তাই টাচ ইভেন্ট শনাক্তকরণ প্রায়শই সাধারণ স্পর্শের চেয়ে নড়াচড়ার উপর বেশি নির্ভর করে। অ্যাপগুলোকে নড়াচড়া-ভিত্তিক জেসচার (যেমন সোয়াইপ) এবং নড়াচড়া-বিহীন জেসচারের (যেমন সিঙ্গেল ট্যাপ) মধ্যে পার্থক্য করতে সাহায্য করার জন্য, অ্যান্ড্রয়েডে ‘টাচ স্লপ’ ধারণাটি অন্তর্ভুক্ত রয়েছে। টাচ স্লপ বলতে পিক্সেলে সেই দূরত্বকে বোঝায়, যা পর্যন্ত একজন ব্যবহারকারীর স্পর্শ একটি জেসচারকে নড়াচড়া-ভিত্তিক জেসচার হিসেবে ব্যাখ্যা করার আগে বিচরণ করতে পারে। এই বিষয়ে আরও তথ্যের জন্য, ‘Manage touch events in a ViewGroup ’ দেখুন।
আপনার অ্যাপ্লিকেশনের প্রয়োজন অনুসারে, কোনো অঙ্গভঙ্গির নড়াচড়া ট্র্যাক করার বিভিন্ন উপায় রয়েছে। নিচে তার কয়েকটি উদাহরণ দেওয়া হলো:
- একটি পয়েন্টারের শুরু এবং শেষের অবস্থান, যেমন স্ক্রিনের কোনো বস্তুকে A বিন্দু থেকে B বিন্দুতে সরানো।
- X এবং Y স্থানাঙ্ক দ্বারা নির্ধারিত পয়েন্টারটির চলার দিক।
- হিস্ট্রি। আপনি
MotionEventএরgetHistorySize()মেথডটি কল করে একটি জেসচারের হিস্ট্রির সাইজ জানতে পারেন। এরপর আপনি মোশন ইভেন্টেরgetHistorical <Value>মেথডগুলো ব্যবহার করে প্রতিটি হিস্টোরিক্যাল ইভেন্টের পজিশন, সাইজ, সময় এবং প্রেসার পেতে পারেন। ব্যবহারকারীর আঙুলের গতিপথ রেন্ডার করার জন্য হিস্ট্রি বেশ দরকারি, যেমন টাচ ড্রয়িং-এর ক্ষেত্রে। বিস্তারিত জানতেMotionEventরেফারেন্স দেখুন। - টাচস্ক্রিন জুড়ে পয়েন্টারটির চলার বেগ।
নিম্নলিখিত সম্পর্কিত উৎসসমূহ দেখুন:
ট্র্যাক বেগ
পয়েন্টারের অতিক্রান্ত দূরত্ব বা দিকের উপর ভিত্তি করে আপনি একটি মুভমেন্ট-ভিত্তিক জেসচার ব্যবহার করতে পারেন। তবে, কোনো জেসচারের বৈশিষ্ট্য ট্র্যাক করতে বা জেসচারটি ঘটেছে কিনা তা নির্ধারণ করতে বেগ প্রায়শই একটি নির্ণায়ক ভূমিকা পালন করে। বেগের হিসাব সহজ করার জন্য, অ্যান্ড্রয়েড VelocityTracker ক্লাসটি প্রদান করে। VelocityTracker আপনাকে টাচ ইভেন্টের বেগ ট্র্যাক করতে সাহায্য করে। এটি সেইসব জেসচারের জন্য উপযোগী, যেখানে বেগ জেসচারটির একটি অন্যতম শর্ত, যেমন ফ্লিং।
এখানে একটি উদাহরণ দেওয়া হলো যা VelocityTracker API-এর মেথডগুলোর উদ্দেশ্য ব্যাখ্যা করে:
কোটলিন
private const val DEBUG_TAG = "Velocity" class MainActivity : Activity() { private var mVelocityTracker: VelocityTracker? = null override fun onTouchEvent(event: MotionEvent): Boolean { when (event.actionMasked) { MotionEvent.ACTION_DOWN -> { // Reset the velocity tracker back to its initial state. mVelocityTracker?.clear() // If necessary, retrieve a new VelocityTracker object to watch // the velocity of a motion. mVelocityTracker = mVelocityTracker ?: VelocityTracker.obtain() // Add a user's movement to the tracker. mVelocityTracker?.addMovement(event) } MotionEvent.ACTION_MOVE -> { mVelocityTracker?.apply { val pointerId: Int = event.getPointerId(event.actionIndex) addMovement(event) // When you want to determine the velocity, call // computeCurrentVelocity(). Then, call getXVelocity() and // getYVelocity() to retrieve the velocity for each pointer // ID. computeCurrentVelocity(1000) // Log velocity of pixels per second. It's best practice to // use VelocityTrackerCompat where possible. Log.d("", "X velocity: ${getXVelocity(pointerId)}") Log.d("", "Y velocity: ${getYVelocity(pointerId)}") } } MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { // Return a VelocityTracker object back to be re-used by others. mVelocityTracker?.recycle() mVelocityTracker = null } } return true } }
জাভা
public class MainActivity extends Activity { private static final String DEBUG_TAG = "Velocity"; ... private VelocityTracker mVelocityTracker = null; @Override public boolean onTouchEvent(MotionEvent event) { int index = event.getActionIndex(); int action = event.getActionMasked(); int pointerId = event.getPointerId(index); switch(action) { case MotionEvent.ACTION_DOWN: if(mVelocityTracker == null) { // Retrieve a new VelocityTracker object to watch the // velocity of a motion. mVelocityTracker = VelocityTracker.obtain(); } else { // Reset the velocity tracker back to its initial state. mVelocityTracker.clear(); } // Add a user's movement to the tracker. mVelocityTracker.addMovement(event); break; case MotionEvent.ACTION_MOVE: mVelocityTracker.addMovement(event); // When you want to determine the velocity, call // computeCurrentVelocity(). Then call getXVelocity() and // getYVelocity() to retrieve the velocity for each pointer ID. mVelocityTracker.computeCurrentVelocity(1000); // Log velocity of pixels per second. It's best practice to use // VelocityTrackerCompat where possible. Log.d("", "X velocity: " + mVelocityTracker.getXVelocity(pointerId)); Log.d("", "Y velocity: " + mVelocityTracker.getYVelocity(pointerId)); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: // Return a VelocityTracker object back to be re-used by others. mVelocityTracker.recycle(); break; } return true; } }
পয়েন্টার ক্যাপচার ব্যবহার করুন
কিছু অ্যাপ, যেমন গেম এবং রিমোট ডেস্কটপ ও ভার্চুয়ালাইজেশন ক্লায়েন্ট, মাউস পয়েন্টারের উপর নিয়ন্ত্রণ পেলে উপকৃত হয়। পয়েন্টার ক্যাপচার হলো অ্যান্ড্রয়েড ৮.০ (এপিআই লেভেল ২৬) এবং এর পরবর্তী সংস্করণগুলোতে উপলব্ধ একটি ফিচার, যা আপনার অ্যাপের কোনো ফোকাস করা ভিউতে সমস্ত মাউস ইভেন্ট পৌঁছে দেওয়ার মাধ্যমে এই নিয়ন্ত্রণ প্রদান করে।
পয়েন্টার ক্যাপচারের অনুরোধ
আপনার অ্যাপের কোনো ভিউ শুধুমাত্র তখনই পয়েন্টার ক্যাপচারের জন্য অনুরোধ করতে পারে, যখন সেটিকে ধারণকারী ভিউ হায়ারার্কিটির উপর ফোকাস থাকে। এই কারণে, ভিউটির উপর কোনো নির্দিষ্ট ইউজার অ্যাকশন চলাকালীন পয়েন্টার ক্যাপচারের জন্য অনুরোধ করুন, যেমন onClick() ইভেন্টের সময় অথবা আপনার অ্যাক্টিভিটির onWindowFocusChanged() ইভেন্ট হ্যান্ডলারে।
পয়েন্টার ক্যাপচারের অনুরোধ করতে, ভিউ-এর উপর ` requestPointerCapture() ` মেথডটি কল করুন। ব্যবহারকারী যখন একটি ভিউ-তে ক্লিক করেন, তখন কীভাবে পয়েন্টার ক্যাপচারের অনুরোধ করতে হয়, তা নিম্নলিখিত কোড উদাহরণে দেখানো হয়েছে:
কোটলিন
fun onClick(view: View) { view.requestPointerCapture() }
জাভা
@Override public void onClick(View view) { view.requestPointerCapture(); }
পয়েন্টার ক্যাপচার করার অনুরোধ সফল হলে, অ্যান্ড্রয়েড onPointerCaptureChange(true) কল করে। যে ভিউটি ক্যাপচারের অনুরোধ করেছে, আপনার অ্যাপের সেই ফোকাস করা ভিউটি যদি একই ভিউ হায়ারার্কিতে থাকে, তবে সিস্টেম সেই ভিউতে মাউস ইভেন্টগুলো পৌঁছে দেয়। ক্যাপচারটি রিলিজ না হওয়া পর্যন্ত অন্যান্য অ্যাপ, এমনকি ACTION_OUTSIDE ইভেন্টগুলোও, মাউস ইভেন্ট পাওয়া বন্ধ করে দেয়। অ্যান্ড্রয়েড মাউস ছাড়া অন্য উৎস থেকে আসা পয়েন্টার ইভেন্টগুলো স্বাভাবিকভাবেই পৌঁছে দেয়, কিন্তু মাউস পয়েন্টারটি আর দেখা যায় না।
ক্যাপচার করা পয়েন্টার ইভেন্টগুলি পরিচালনা করুন
কোনো ভিউ সফলভাবে পয়েন্টার ক্যাপচার করার পর, অ্যান্ড্রয়েড মাউস ইভেন্টগুলো প্রেরণ করে। আপনার ফোকাস করা ভিউটি নিম্নলিখিত কাজগুলোর মধ্যে যেকোনো একটি সম্পাদন করে এই ইভেন্টগুলো পরিচালনা করতে পারে:
- আপনি যদি কাস্টম ভিউ ব্যবহার করেন, তাহলে
onCapturedPointerEvent(MotionEvent)ওভাররাইড করুন। - অন্যথায়, একটি
OnCapturedPointerListenerরেজিস্টার করুন।
নিম্নলিখিত কোড উদাহরণটি দেখায় কিভাবে onCapturedPointerEvent(MotionEvent) প্রয়োগ করতে হয়:
কোটলিন
override fun onCapturedPointerEvent(motionEvent: MotionEvent): Boolean { // Get the coordinates required by your app. val verticalOffset: Float = motionEvent.y // Use the coordinates to update your view and return true if the event is // successfully processed. return true }
জাভা
@Override public boolean onCapturedPointerEvent(MotionEvent motionEvent) { // Get the coordinates required by your app. float verticalOffset = motionEvent.getY(); // Use the coordinates to update your view and return true if the event is // successfully processed. return true; }
নিম্নলিখিত কোড উদাহরণটি দেখায় কিভাবে একটি OnCapturedPointerListener নিবন্ধন করতে হয়:
কোটলিন
myView.setOnCapturedPointerListener { view, motionEvent -> // Get the coordinates required by your app. val horizontalOffset: Float = motionEvent.x // Use the coordinates to update your view and return true if the event is // successfully processed. true }
জাভা
myView.setOnCapturedPointerListener(new View.OnCapturedPointerListener() { @Override public boolean onCapturedPointer (View view, MotionEvent motionEvent) { // Get the coordinates required by your app. float horizontalOffset = motionEvent.getX(); // Use the coordinates to update your view and return true if the event is // successfully processed. return true; } });
আপনি কাস্টম ভিউ ব্যবহার করুন বা লিসেনার রেজিস্টার করুন, আপনার ভিউ একটি MotionEvent গ্রহণ করে যাতে পয়েন্টার কোঅর্ডিনেট থাকে। এই কোঅর্ডিনেটগুলো X বা Y ডেল্টার মতো আপেক্ষিক মুভমেন্ট নির্দিষ্ট করে, যা একটি ট্র্যাকবল ডিভাইস থেকে পাওয়া কোঅর্ডিনেটের অনুরূপ। আপনি getX() এবং getY() ব্যবহার করে এই কোঅর্ডিনেটগুলো পেতে পারেন।
রিলিজ পয়েন্টার ক্যাপচার
আপনার অ্যাপের ভিউ releasePointerCapture() কল করার মাধ্যমে পয়েন্টার ক্যাপচারটি মুক্ত করতে পারে, যেমনটি নিম্নলিখিত কোড উদাহরণে দেখানো হয়েছে:
কোটলিন
override fun onClick(view: View) { view.releasePointerCapture() }
জাভা
@Override public void onClick(View view) { view.releasePointerCapture(); }
আপনি স্পষ্টভাবে releasePointerCapture() কল না করলেও সিস্টেম ভিউটি থেকে ক্যাপচারটি সরিয়ে নিতে পারে, এর সাধারণ কারণ হলো যে ভিউটি ক্যাপচারের অনুরোধ করে, সেই ভিউ হায়ারার্কিটি ফোকাস হারিয়ে ফেলে।
