টাচ ও পয়েন্টারের মুভমেন্ট ট্র্যাক করুন

Compose-এর মাধ্যমে চেষ্টা করুন
Jetpack Compose হল Android-এর জন্য সাজেস্ট করা UI টুলকিট। Compose-এ কীভাবে টাচ ও ইনপুট ব্যবহার করতে হয় তা জানুন।

টাচ ইভেন্টে কীভাবে মুভমেন্ট ট্র্যাক করতে হয় তা এই পাঠে বর্ণনা করা হয়েছে।

বর্তমান টাচ কন্ট্যাক্ট পজিশন, প্রেসার বা সাইজ পরিবর্তন হলে, ACTION_MOVE ইভেন্টের মাধ্যমে একটি নতুন onTouchEvent() ট্রিগার হয়। সাধারণ জেসচার শনাক্ত করুন বিভাগে যেমন বর্ণনা করা হয়েছে, এইসব ইভেন্ট onTouchEvent()-এর MotionEvent প্যারামিটারে রেকর্ড করা হয়।

আঙুল দিয়ে টাচ করা সবসময় সবচেয়ে নিখুঁত ইন্টার‍্যাকশন হয় না, তাই টাচ ইভেন্ট শনাক্ত করার সময় শুধু টাচ করার চেয়ে মুভমেন্টের উপর বেশি জোর দেওয়া হয়। মুভমেন্ট-ভিত্তিক জেসচার (যেমন সোয়াইপ) এবং নন-মুভমেন্ট জেসচারের (যেমন একবার ট্যাপ করা) মধ্যে পার্থক্য করতে অ্যাপকে সাহায্য করার জন্য, Android-এ টাচ স্লপ-এর ধারণা অন্তর্ভুক্ত করা হয়েছে। টাচ স্লোপ বলতে পিক্সেলের দূরত্বকে বোঝায় যা ব্যবহারকারীর টাচ মুভমেন্ট-ভিত্তিক জেসচার হিসেবে ব্যাখ্যা করার আগে ঘুরে বেড়াতে পারে। এই বিষয়ে আরও জানতে, ViewGroup-এ টাচ ইভেন্ট ম্যানেজ করা দেখুন।

আপনার অ্যাপ্লিকেশনের প্রয়োজনের উপর নির্ভর করে, জেসচারে মুভমেন্ট ট্র্যাক করার একাধিক উপায় আছে। নিচে কিছু উদাহরণ দেওয়া হল:

  • পয়েন্টারের শুরু ও শেষের পজিশন, যেমন স্ক্রিনে কোনও অবজেক্টকে পয়েন্ট A থেকে পয়েন্ট B-তে সরানো।
  • X ও Y কোঅর্ডিনেট দ্বারা নির্ধারিত, পয়েন্টার যে দিকে যাচ্ছে।
  • ইতিহাস। আপনি MotionEvent পদ্ধতি getHistorySize() কল করে কোনও জেসচারের ইতিহাসের সাইজ খুঁজে পেতে পারেন। তারপর আপনি মোশন ইভেন্টের getHistorical<Value> পদ্ধতি ব্যবহার করে প্রতিটি ঐতিহাসিক ইভেন্টের অবস্থান, সাইজ, সময় ও প্রেসার সংক্রান্ত তথ্য পেতে পারেন। ব্যবহারকারীর আঙুলের ট্রেল রেন্ডার করার সময় ইতিহাস কাজে লাগে, যেমন টাচ ড্রয়িংয়ের ক্ষেত্রে। আরও বিবরণের জন্য MotionEvent রেফারেন্স দেখুন।
  • টাচস্ক্রিন জুড়ে পয়েন্টার সরানোর সময় সেটির গতি।

নিম্নলিখিত সম্পর্কিত রিসোর্স দেখুন:

ট্র্যাকের গতিবেগ

আপনি মুভমেন্ট-ভিত্তিক জেসচার ব্যবহার করতে পারেন যা পয়েন্টার কতটা দূরত্ব বা কোন দিকে যাচ্ছে তার উপর নির্ভর করে। তবে, কোনও জেসচারের বৈশিষ্ট্য ট্র্যাক করা বা জেসচারটি করা হয়েছে কিনা তা নির্ধারণ করার ক্ষেত্রে গতিবেগ প্রায়শই একটি নির্ধারক ফ্যাক্টর হিসেবে কাজ করে। গতিবেগ গণনা করা সহজ করতে, Android VelocityTracker ক্লাস প্রদান করে। VelocityTracker আপনাকে টাচ ইভেন্টের গতি ট্র্যাক করতে সাহায্য করে। এটি সেইসব জেসচারের ক্ষেত্রে উপযোগী যেগুলিতে জেসচারের মানদণ্ডের অংশ হিসেবে বেগ থাকে, যেমন ফ্লিং।

এখানে একটি উদাহরণ দেওয়া হল যা VelocityTracker API-তে পদ্ধতির উদ্দেশ্য ব্যাখ্যা করে:

Kotlin

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;
    }
}

পয়েন্টার ক্যাপচার ব্যবহার করুন

গেম, রিমোট ডেস্কটপ ও ভার্চুয়ালাইজেশন ক্লায়েন্টের মতো কিছু অ্যাপ মাউস পয়েন্টারের উপর নিয়ন্ত্রণ পেলে আরও ভালভাবে কাজ করতে পারে। পয়েন্টার ক্যাপচার হল Android 8.0 (API লেভেল ২৬) এবং তার পরবর্তী ভার্সনে উপলভ্য একটি ফিচার যা আপনার অ্যাপের ফোকাস করা ভিউতে সব মাউস ইভেন্ট ডেলিভার করার মাধ্যমে এই কন্ট্রোল প্রদান করে।

পয়েন্টার ক্যাপচার করার অনুরোধ করুন

আপনার অ্যাপের কোনও ভিউ তখনই পয়েন্টার ক্যাপচারের অনুরোধ করতে পারে যখন সেটির ভিউ হায়ারার্কি ফোকাসে থাকে। এই কারণে, ভিউতে কোনও নির্দিষ্ট ব্যবহারকারীর অ্যাকশন থাকলে, যেমন onClick() ইভেন্ট চলাকালীন বা আপনার অ্যাক্টিভিটির onWindowFocusChanged() ইভেন্ট হ্যান্ডলারে, পয়েন্টার ক্যাপচারের অনুরোধ করুন।

পয়েন্টার ক্যাপচার করার অনুরোধ করতে, ভিউতে requestPointerCapture() মেথড কল করুন। ব্যবহারকারী কোনও ভিউতে ক্লিক করলে কীভাবে পয়েন্টার ক্যাপচার করার অনুরোধ করতে হয় তা নিম্নলিখিত কোডের উদাহরণ থেকে দেখানো হয়েছে:

Kotlin

fun onClick(view: View) {
    view.requestPointerCapture()
}

জাভা

@Override
public void onClick(View view) {
    view.requestPointerCapture();
}

পয়েন্টার ক্যাপচার করার অনুরোধ সফল হলে, Android onPointerCaptureChange(true) কল করে। সিস্টেম আপনার অ্যাপের ফোকাস করা ভিউতে মাউস ইভেন্ট ডেলিভার করে যতক্ষণ না এটি ক্যাপচারের অনুরোধ করা ভিউয়ের মতো একই ভিউ হায়ারার্কিতে থাকে। ক্যাপচার রিলিজ না হওয়া পর্যন্ত অন্যান্য অ্যাপ মাউস ইভেন্ট রিসিভ করা বন্ধ করে দেয়, যার মধ্যে ACTION_OUTSIDE ইভেন্টও অন্তর্ভুক্ত। Android, মাউস ছাড়া অন্যান্য সোর্স থেকে পয়েন্টার ইভেন্ট স্বাভাবিকভাবে ডেলিভার করে, তবে মাউস পয়েন্টার আর দেখা যায় না।

ক্যাপচার করা পয়েন্টার ইভেন্ট ম্যানেজ করুন

কোনও ভিউ সফলভাবে পয়েন্টার ক্যাপচার অ্যাকোয়ার করলে, Android মাউস ইভেন্ট ডেলিভার করে। আপনার ফোকাস করা ভিউ নিম্নলিখিত টাস্কের মধ্যে একটি সম্পূর্ণ করার মাধ্যমে ইভেন্ট ম্যানেজ করতে পারে:

নিম্নলিখিত কোডের উদাহরণ থেকে কীভাবে onCapturedPointerEvent(MotionEvent) প্রয়োগ করতে হয় তা দেখানো হয়েছে:

Kotlin

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 রেজিস্টার করতে হয়:

Kotlin

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() কল করে পয়েন্টার ক্যাপচার রিলিজ করতে পারে, যেমনটি নিম্নলিখিত কোড উদাহরণে দেখানো হয়েছে:

Kotlin

override fun onClick(view: View) {
    view.releasePointerCapture()
}

জাভা

@Override
public void onClick(View view) {
    view.releasePointerCapture();
}

আপনি স্পষ্টভাবে releasePointerCapture() কল না করলেও, সিস্টেম ভিউ থেকে ক্যাপচার সরিয়ে দিতে পারে, সাধারণত কারণ হল, ক্যাপচারের অনুরোধ করা ভিউ যে ভিউ হায়ারার্কিতে রয়েছে, সেটি ফোকাস হারিয়ে ফেলে।