सवाल एंड्रॉइड: पता लगाएँ कि क्या उपयोगकर्ता बटन क्षेत्र से छूता है और ड्रैग करता है?


एंड्रॉइड में, हम कैसे पता लगा सकते हैं कि कोई उपयोगकर्ता बटन पर छूता है और इस बटन के क्षेत्र से बाहर निकलता है?


44
2018-06-20 11:03


मूल




जवाब:


मोशनवेन्ट की जांच करें। MOVE_OUTSIDE: मोशनवेन्ट की जांच करें। MOVE:

private Rect rect;    // Variable rect to hold the bounds of the view

public boolean onTouch(View v, MotionEvent event) {
    if(event.getAction() == MotionEvent.ACTION_DOWN){
        // Construct a rect of the view's bounds
        rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());

    }
    if(event.getAction() == MotionEvent.ACTION_MOVE){
        if(!rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY())){
            // User moved outside bounds
        }
    }
    return false;
}

नोट: यदि आप एंड्रॉइड 4.0 को लक्षित करना चाहते हैं, तो नई संभावनाओं की पूरी दुनिया खुलती है: http://developer.android.com/reference/android/view/MotionEvent.html#ACTION_HOVER_ENTER


81
2017-11-09 18:42



क्षमा करें लेकिन यह काम नहीं करता है। मैं केवल ACTION_UP, ACTION_DOWN और ACTION_MOVE को पकड़ सकता हूं लेकिन ACTION_OUTSIDE नहीं। - anticafe
यह एपीआई स्तर 3 से आगे उपलब्ध है: developer.android.com/reference/android/view/... - Entreco
इस उत्तर के अनुसार (stackoverflow.com/questions/6162497/...) मेरा मानना ​​है कि हम केवल ACTION_OUTSIDE का उपयोग यह पता लगाने के लिए कर सकते हैं कि स्पर्श गतिविधि के बाहर है या नहीं। - anticafe
आपका अधिकार! मैंने अपना जवाब संशोधित कर दिया है - Entreco
मूल कार्य में स्थित व्यक्तिगत विचारों के लिए यह काम करने के लिए rect.contains परीक्षण के लिए अद्यतन के लिए FrostRocket का उत्तर देखें। - Dan J


एंट्रेको द्वारा पोस्ट किए गए उत्तर को मेरे मामले में कुछ मामूली tweaking की जरूरत है। मुझे प्रतिस्थापित करना पड़ा:

if(!rect.contains((int)event.getX(), (int)event.getY()))

के लिये

if(!rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY()))

इसलिये event.getX() तथा event.getY() केवल छवि दृश्य पर ही लागू करें, पूरी स्क्रीन पर नहीं।


21
2018-01-04 05:46



+1 धन्यवाद, यह अधिक सार्वभौमिक दृष्टिकोण है और कस्टम व्यू कार्यान्वयन में भी काम करता है - Knickedi


मैंने अपने ऑन टच में कुछ लॉगिंग जोड़ा और उसे पता चला MotionEvent.ACTION_CANCEL मारा जा रहा था। यह मेरे लिए काफी अच्छा है ...


5
2018-05-25 14:49



आपको एक मिल जाएगा MotionEvent.ACTION_CANCEL अगर आपका कॉलबैक है View एक माता पिता के भीतर निहित है ViewGroup पसंद ScrollView जो अपने बच्चों से चाल छूने में दिलचस्पी लेता है लेकिन अन्यथा कोई गारंटी नहीं है कि आपको एक प्राप्त होगा MotionEvent.ACTION_CANCEL आपके में कॉलबैक View। - Adil Hussain


जब शीर्ष दृश्य स्क्रॉलव्यू के अंदर होता है तो शीर्ष 2 उत्तरों ठीक होते हैं: जब स्क्रॉलिंग होती है क्योंकि आप अपनी उंगली ले जाते हैं, यह अभी भी टच इवेंट के रूप में पंजीकृत है लेकिन मोशनएवेंट.एक्शन_MOVE ईवेंट के रूप में नहीं। तो उत्तर में सुधार करने के लिए (केवल तभी जरूरी है जब आपका दृश्य स्क्रॉल तत्व के अंदर है):

private Rect rect;    // Variable rect to hold the bounds of the view

public boolean onTouch(View v, MotionEvent event) {
    if(event.getAction() == MotionEvent.ACTION_DOWN){
        // Construct a rect of the view's bounds
        rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());

    } else if(rect != null && !rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY())){
        // User moved outside bounds
    }
    return false;
}

मैंने एंड्रॉइड 4.3 और एंड्रॉइड 4.4 पर इसका परीक्षण किया

मैंने मोरित्ज़ के जवाब और शीर्ष 2 के बीच कोई अंतर नहीं देखा है, लेकिन यह उनके उत्तर के लिए भी लागू होता है:

private Rect rect;    // Variable rect to hold the bounds of the view

public boolean onTouch(View v, MotionEvent event) {
    if(event.getAction() == MotionEvent.ACTION_DOWN){
        // Construct a rect of the view's bounds
        rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());

    } else if (rect != null){
        v.getHitRect(rect);
        if(rect.contains(
                Math.round(v.getX() + event.getX()),
                Math.round(v.getY() + event.getY()))) {
            // inside
        } else {
            // outside
        }
    }
    return false;
}

2
2018-04-14 08:05



मैंने अभी इस कोड को एक बटन पर कार्यान्वित किया है जो एक RecyclerView के किसी आइटम में निहित है और पूरी तरह से काम करता है। मैं सिर्फ यह कहना चाहता था कि आप नए रेक्ट से छुटकारा पा सकते हैं ACTION_DOWN अगर आप getHitRect से पहले इसे जोड़ते हैं। Rect rect = नया Rect (); getHitRect (रेक्ट); - Jose M Lechon


मुझे ओपी के समान समस्या थी जिससे मैं जानना चाहता था कि (1) एक विशेष View नीचे स्पर्श किया गया था और साथ ही (2) जब नीचे स्पर्श जारी किया गया था View या (3) जब नीचे स्पर्श की सीमाओं के बाहर चले गए View। मैंने एक सरल विस्तार बनाने के लिए इस धागे में विभिन्न उत्तरों को एक साथ लाया View.OnTouchListener (नाम SimpleTouchListener) ताकि दूसरों को इसके साथ घूमना पड़े MotionEvent वस्तु। कक्षा के लिए स्रोत पाया जा सकता है यहाँ या इस उत्तर के नीचे।

इस वर्ग का उपयोग करने के लिए, इसे बस के एकल पैरामीटर के रूप में सेट करें View.setOnTouchListener(View.OnTouchListener) विधि निम्नानुसार है:

myView.setOnTouchListener(new SimpleTouchListener() {

    @Override
    public void onDownTouchAction() {
        // do something when the View is touched down
    }

    @Override
    public void onUpTouchAction() {
        // do something when the down touch is released on the View
    }

    @Override
    public void onCancelTouchAction() {
        // do something when the down touch is canceled
        // (e.g. because the down touch moved outside the bounds of the View
    }
});

यहां कक्षा का स्रोत है जिसे आप अपनी परियोजना में जोड़ सकते हैं:

public abstract class SimpleTouchListener implements View.OnTouchListener {

    /**
     * Flag determining whether the down touch has stayed with the bounds of the view.
     */
    private boolean touchStayedWithinViewBounds;

    @Override
    public boolean onTouch(View view, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                touchStayedWithinViewBounds = true;
                onDownTouchAction();
                return true;

            case MotionEvent.ACTION_UP:
                if (touchStayedWithinViewBounds) {
                    onUpTouchAction();
                }
                return true;

            case MotionEvent.ACTION_MOVE:
                if (touchStayedWithinViewBounds
                        && !isMotionEventInsideView(view, event)) {
                    onCancelTouchAction();
                    touchStayedWithinViewBounds = false;
                }
                return true;

            case MotionEvent.ACTION_CANCEL:
                onCancelTouchAction();
                return true;

            default:
                return false;
        }
    }

    /**
     * Method which is called when the {@link View} is touched down.
     */
    public abstract void onDownTouchAction();

    /**
     * Method which is called when the down touch is released on the {@link View}.
     */
    public abstract void onUpTouchAction();

    /**
     * Method which is called when the down touch is canceled,
     * e.g. because the down touch moved outside the bounds of the {@link View}.
     */
    public abstract void onCancelTouchAction();

    /**
     * Determines whether the provided {@link MotionEvent} represents a touch event
     * that occurred within the bounds of the provided {@link View}.
     *
     * @param view  the {@link View} to which the {@link MotionEvent} has been dispatched.
     * @param event the {@link MotionEvent} of interest.
     * @return true iff the provided {@link MotionEvent} represents a touch event
     * that occurred within the bounds of the provided {@link View}.
     */
    private boolean isMotionEventInsideView(View view, MotionEvent event) {
        Rect viewRect = new Rect(
                view.getLeft(),
                view.getTop(),
                view.getRight(),
                view.getBottom()
        );

        return viewRect.contains(
                view.getLeft() + (int) event.getX(),
                view.getTop() + (int) event.getY()
        );
    }
}

2
2018-03-26 16:09



यह एक अच्छा जवाब है, खासतौर से इस मुद्दे के साथ काम करने वाले लोगों के लिए जब ACTION_CANCEL इसे ट्रिगर नहीं कर रहा है। - New Guy


जबकि @FrostRocket का उत्तर सही है, आपको view.getX () और Y का उपयोग अनुवाद परिवर्तनों के लिए भी करना चाहिए:

 view.getHitRect(viewRect);
 if(viewRect.contains(
         Math.round(view.getX() + event.getX()),
         Math.round(view.getY() + event.getY()))) {
   // inside
 } else {
   // outside
 }

1
2017-10-17 10:37





view.setClickable(true);
view.setOnTouchListener(new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (!v.isPressed()) {
            Log.e("onTouch", "Moved outside view!");
        }
        return false;
    }
});

view.isPressed का उपयोग करता है view.pointInView और कुछ टच ढलान भी शामिल है। यदि आप ढलान नहीं चाहते हैं, तो तर्क को आंतरिक से कॉपी करें view.pointInView (जो सार्वजनिक है, लेकिन छुपा है इसलिए यह आधिकारिक एपीआई का हिस्सा नहीं है और किसी भी समय गायब हो सकता है)।

view.setClickable(true);
view.setOnTouchListener(new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            v.setTag(true);
        } else {
            boolean pointInView = event.getX() >= 0 && event.getY() >= 0
                    && event.getX() < (getRight() - getLeft())
                    && event.getY() < (getBottom() - getTop());
            boolean eventInView = ((boolean) v.getTag()) && pointInView;
            Log.e("onTouch", String.format("Dragging currently in view? %b", pointInView));
            Log.e("onTouch", String.format("Dragging always in view? %b", eventInView));
            v.setTag(eventInView);
        }
        return false;
    }
});

1
2017-10-06 22:17





यहां है View.OnTouchListener कि आप यह देखने के लिए उपयोग कर सकते हैं कि क्या MotionEvent.ACTION_UP भेजा गया था जब उपयोगकर्ता के पास उसकी उंगली दृश्य के बाहर थी:

private OnTouchListener mOnTouchListener = new View.OnTouchListener() {

    private Rect rect;

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (v == null) return true;
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
            return true;
        case MotionEvent.ACTION_UP:
            if (rect != null
                    && !rect.contains(v.getLeft() + (int) event.getX(),
                        v.getTop() + (int) event.getY())) {
                // The motion event was outside of the view, handle this as a non-click event

                return true;
            }
            // The view was clicked.
            // TODO: do stuff
            return true;
        default:
            return true;
        }
    }
};

0
2018-01-19 09:04