हाथ के सामान्य जेस्चर का पता लगाना

Compose को आज़माएं
Android के लिए, Jetpack Compose को यूज़र इंटरफ़ेस (यूआई) टूलकिट के तौर पर इस्तेमाल करने का सुझाव दिया जाता है. Compose में टच और इनपुट का इस्तेमाल करने का तरीका जानें.

टच जेस्चर तब होता है, जब कोई उपयोगकर्ता टचस्क्रीन पर एक या उससे ज़्यादा उंगलियां रखता है और आपका ऐप्लिकेशन, टच के इस पैटर्न को जेस्चर के तौर पर समझता है. जेस्चर की पहचान करने के दो चरण होते हैं:

  1. टच इवेंट का डेटा इकट्ठा करना.
  2. यह तय करने के लिए डेटा की व्याख्या करना कि यह आपके ऐप्लिकेशन के साथ काम करने वाले जेस्चर की ज़रूरी शर्तें पूरी करता है या नहीं.

AndroidX क्लास

इस दस्तावेज़ में दिए गए उदाहरणों में, GestureDetectorCompat और MotionEventCompat क्लास का इस्तेमाल किया गया है. ये क्लास, AndroidX Library में मौजूद हैं. पहले के डिवाइसों के साथ काम करने की सुविधा देने के लिए, जहां भी हो सके AndroidX क्लास का इस्तेमाल करें. MotionEventCompat क्लास का विकल्प नहीं है.MotionEvent इसके बजाय, यह स्टैटिक यूटिलिटी के तरीके उपलब्ध कराता है. इनमें, आपको अपना MotionEvent ऑब्जेक्ट पास करना होता है, ताकि उस इवेंट से जुड़ी कार्रवाई की जानकारी मिल सके.

डेटा इकट्ठा करना

जब कोई उपयोगकर्ता स्क्रीन पर एक या ज़्यादा उंगलियां रखता है, तो इससे उस व्यू पर कॉलबैक onTouchEvent() ट्रिगर होता है जिसे टच इवेंट मिलते हैं. टच इवेंट के हर क्रम के लिए—जैसे कि पोज़िशन, प्रेशर, साइज़, और एक और उंगली जोड़ना—जिसे जेस्चर के तौर पर पहचाना जाता है, onTouchEvent() कई बार ट्रिगर होता है.

जेस्चर तब शुरू होता है, जब उपयोगकर्ता पहली बार स्क्रीन को छूता है. यह तब तक जारी रहता है, जब तक सिस्टम उपयोगकर्ता की उंगली या उंगलियों की पोज़िशन को ट्रैक करता है. यह तब खत्म होता है, जब उपयोगकर्ता की आखिरी उंगली स्क्रीन से हट जाती है. इस इंटरैक्शन के दौरान, onTouchEvent() को दिया गया MotionEvent, हर इंटरैक्शन की जानकारी देता है. MotionEvent से मिले डेटा का इस्तेमाल करके, आपका ऐप्लिकेशन यह तय कर सकता है कि कोई ऐसा जेस्चर हुआ है या नहीं जिसे वह ट्रैक करना चाहता है.

किसी गतिविधि या व्यू के लिए टच इवेंट कैप्चर करना

किसी Activity या View में टच इवेंट को इंटरसेप्ट करने के लिए, onTouchEvent() कॉलबैक को बदलें.

नीचे दिए गए कोड स्निपेट में, getAction() का इस्तेमाल करके, event पैरामीटर से उपयोगकर्ता की कार्रवाई को एक्सट्रैक्ट किया गया है. इससे आपको वह रॉ डेटा मिलता है जिसकी मदद से यह तय किया जा सकता है कि कोई ऐसा जेस्चर हुआ है या नहीं जिसे आप ट्रैक करना चाहते हैं.

Kotlin

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

Java

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 की मदद से, सामान्य जेस्चर को आसानी से पहचाना जा सकता है. इसके लिए, आपको अलग-अलग टच इवेंट को प्रोसेस करने की ज़रूरत नहीं होती. इस बारे में, जेस्चर की पहचान करना लेख में ज़्यादा जानकारी दी गई है.

किसी एक व्यू के लिए टच इवेंट कैप्चर करना

onTouchEvent() के विकल्प के तौर पर, View.OnTouchListener ऑब्जेक्ट को किसी भी View ऑब्जेक्ट में setOnTouchListener() तरीके का इस्तेमाल करके जोड़ा जा सकता है. इससे, मौजूदा View की सबक्लासिंग किए बिना, टच इवेंट को सुना जा सकता है. जैसा कि यहां दिए गए उदाहरण में दिखाया गया है:

Kotlin

findViewById<View>(R.id.my_view).setOnTouchListener { v, event ->
    // Respond to touch events.
    true
}

Java

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() को बदला जा सकता है.

जेस्चर की पहचान करना

Android, सामान्य जेस्चर की पहचान करने के लिए GestureDetector क्लास उपलब्ध कराता है. यह onDown(), onLongPress(), और onFling() जैसे कुछ जेस्चर के साथ काम करता है. GestureDetector का इस्तेमाल, पहले बताए गए onTouchEvent() तरीके के साथ किया जा सकता है.

साथ काम करने वाले सभी जेस्चर की पहचान करना

जब GestureDetectorCompat ऑब्जेक्ट को इंस्टैंशिएट किया जाता है, तो इसके पैरामीटर में से एक, GestureDetector.OnGestureListener इंटरफ़ेस को लागू करने वाली क्लास होती है. GestureDetector.OnGestureListener , किसी खास टच इवेंट के होने पर उपयोगकर्ताओं को सूचना देता है. अपने GestureDetector ऑब्जेक्ट को इवेंट पाने की अनुमति देने के लिए, व्यू या गतिविधि के onTouchEvent() तरीके को बदलें और देखे गए सभी इवेंट को डिटेक्टर इंस्टेंस में पास करें.

यहां दिए गए स्निपेट में, true की रिटर्न वैल्यू का मतलब है कि टच इवेंट को मैनेज किया गया है.on<TouchEvent> false की रिटर्न वैल्यू, व्यू स्टैक के ज़रिए इवेंट को तब तक पास करती है, जब तक टच को मैनेज नहीं किया जाता.

अगर टेस्ट ऐप्लिकेशन में, यहां दिया गया स्निपेट चलाया जाता है, तो यह समझा जा सकता है कि टचस्क्रीन के साथ इंटरैक्ट करने पर, कार्रवाइयां कैसे ट्रिगर होती हैं. साथ ही, हर टच इवेंट के लिए MotionEvent का कॉन्टेंट क्या होता है. इसके बाद, यह देखा जा सकता है कि सामान्य इंटरैक्शन के लिए कितना डेटा जनरेट हो रहा है.

Kotlin

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
    }

}

Java

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.OnGestureListener के अन्य तरीकों को कॉल नहीं किया जाता. GestureDetector.SimpleOnGestureListener डिफ़ॉल्ट रूप से ऐसा करता है. इससे आपके ऐप्लिकेशन में अनचाही समस्याएं आ सकती हैं. onDown() से false की वैल्यू सिर्फ़ तब दिखाएं, जब आपको किसी पूरे जेस्चर को अनदेखा करना हो.

Kotlin

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

Java

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

अन्य संसाधन