क्या किसी दृश्य के क्लिक लक्ष्य का आकार बढ़ाने के लिए एंड्रॉइड में टचडेलगेट का उपयोग करने का एक उदाहरण है?


82

मेरी समझ यह है कि जब आपके पास एक ऐसा दृश्य होता है जो आसानी से छूने के लिए बहुत छोटा होता है, तो आपको उस दृश्य के लिए क्लिक करने योग्य क्षेत्र को बढ़ाने के लिए एक टचडेलगेट का उपयोग करना चाहिए।

हालाँकि, Google पर उपयोग उदाहरणों की खोज में कई लोग सवाल पूछ रहे हैं, लेकिन कुछ जवाब भी।

क्या किसी को एक दृश्य प्रतिनिधि के लिए एक टच डेलीगेट सेट करने, कहने, उसके क्लिक करने योग्य क्षेत्र को हर दिशा में 4 पिक्सेल बढ़ाने का उचित तरीका पता है?


3
यहां तरीका देखें: TouchDelegate उपयोग करने के लिए पर एक अतिरिक्त अच्छा पोस्ट है groups.google.com/group/android-developers/browse_thread/thread/...
— मेसन ली

जवाबों:


100

मैंने Google पर एक मित्र से पूछा और वे मुझे पता लगाने में सक्षम थे कि टचडेलगेट का उपयोग कैसे किया जाए। यहाँ हम क्या लेकर आए हैं:

final View parent = (View) delegate.getParent();
parent.post( new Runnable() {
    // Post in the parent's message queue to make sure the parent
    // lays out its children before we call getHitRect()
    public void run() {
        final Rect r = new Rect();
        delegate.getHitRect(r);
        r.top -= 4;
        r.bottom += 4;
        parent.setTouchDelegate( new TouchDelegate( r , delegate));
    }
});

16
क्या होगा अगर एक स्क्रीन पर दो बटन हैं जो आप ऐसा करना चाहते हैं? यदि आप फिर से TouchDelegate सेट करते हैं तो यह पिछले टच डेलीगेट को मिटा देता है।
— कपासबेलपॉज

2
यह एक मेरे लिए काम नहीं किया ... मुझे लगता है कि प्रतिनिधि मैं टचडेलगेट को जोड़ने की कोशिश कर रहा हूं।
— केविन पार्कर

20
@AmokraneChentir मेरे पास एक ही मुद्दा है। टचडेलगेट्स का उपयोग करने के बजाय, मेरे पास एक वर्ग है जो बटन का विस्तार करता है। इस वर्ग में मैं getHitRect को ओवरराइड करता हूं। आप पैरेंट व्यू के आकार को हिट आयत बढ़ा सकते हैं। public void getHitRect (Rect outRect) {outRect.set (getLeft () - mPadding, getTop () - mPadding, getRight () + mPadding, getTop () + mPadding); }
— ब्रेंडन वेनस्टेन

5
@Amokrane: यह ICS में काम न करने वाले समाधान को बताता है। मैंने दो अलग-अलग टच डेलिगेट रणनीतियों brendanweinstein.me/2012/06/26/… पर एक ब्लॉग पोस्ट लिखी है और आप दोनों रणनीतियों के लिए github.com/brendanw/Touch-Delegates/bebb/master/src/com/
— ब्रेंडन वीनस्टीन

8
प्रति @ZsoltSafrany, ऐसा करने का एक सुरक्षित तरीका एक OnGlobalLayoutListener है और प्रतिनिधि को OnGlobalLayout () असाइन कर रहा है।
— greg7gkb

20

मैं इस ब्लॉग पोस्ट से बड़े पैमाने पर एक स्क्रीन ड्राइंग पर कई दृश्यों (चेकबॉक्स) के साथ इसे पूरा करने में सक्षम था । मूल रूप से आप ईमबी का घोल लेते हैं और इसे प्रत्येक बटन और उसके माता-पिता पर व्यक्तिगत रूप से लागू करते हैं।

public static void expandTouchArea(final View bigView, final View smallView, final int extraPadding) {
    bigView.post(new Runnable() {
        @Override
        public void run() {
            Rect rect = new Rect();
            smallView.getHitRect(rect);
            rect.top -= extraPadding;
            rect.left -= extraPadding;
            rect.right += extraPadding;
            rect.bottom += extraPadding;
            bigView.setTouchDelegate(new TouchDelegate(rect, smallView));
        }
   });
}

मेरे मामले में मेरे पास शीर्ष पर चेकबॉक्स के साथ इमेजव्यू का ग्रिडव्यू था, और इस विधि को निम्नानुसार कहा जाता है:

CheckBox mCheckBox = (CheckBox) convertView.findViewById(R.id.checkBox1);
final ImageView imageView = (ImageView) convertView.findViewById(R.id.imageView1);

// Increase checkbox clickable area
expandTouchArea(imageView, mCheckBox, 100);

मेरे लिए बहुत अच्छा काम कर रहा है।


11

इस समाधान को टिप्पणियों में @BrendanWeinstein द्वारा पोस्ट किया गया था।

भेजने के बजाय TouchDelegateआप अपनी getHitRect(Rect)विधि को ओवरराइड कर सकते हैं View(यदि आप एक का विस्तार कर रहे हैं तो)।

public class MyView extends View {  //NOTE: any other View can be used here

    /* a lot of required methods */

    @Override
    public void getHitRect(Rect r) {
        super.getHitRect(r); //get hit Rect of current View

        if(r == null) {
            return;
        }

        /* Manipulate with rect as you wish */
        r.top -= 10;
    }
}

दिलचस्प विचार है। लेकिन क्या इसका मतलब यह नहीं होगा कि दृश्य एक लेआउट से नहीं बनाया जा सकता है? नहीं, प्रतीक्षा करें - यदि मैं एक नया दृश्य वर्ग डिज़ाइन करता हूं और लेआउट में इसका उपयोग करता हूं। वह काम कर सकता था। एक कोशिश के काबिल है।
— मार्टिन

10
@ मार्टिन यही सही विचार है। दुर्भाग्यवश, getHitRect को अब ICS के रूप में नहीं बुलाया जाता है, जिसे डिस्पैचच्यूवेंट grepcode.com/file/repository.grepcode.com/java/ext/… ओवरराइडिंग getHitRect केवल जिंजरब्रेड और नीचे काम करेगा।
— ब्रेंडन वीनस्टीन

6

एम्मी का एप्रोच मेरे लिए काम नहीं आया लेकिन थोड़े बदलाव के बाद इसने किया:

private void initApplyButtonOnClick() {
    mApplyButton.setOnClickListener(onApplyClickListener);
    final View parent = (View)mApplyButton.getParent();
    parent.post(new Runnable() {

        @Override
        public void run() {
            final Rect hitRect = new Rect();
            parent.getHitRect(hitRect);
            hitRect.right = hitRect.right - hitRect.left;
            hitRect.bottom = hitRect.bottom - hitRect.top;
            hitRect.top = 0;
            hitRect.left = 0;
            parent.setTouchDelegate(new TouchDelegate(hitRect , mApplyButton));         
        }
    });
}

शायद यह किसी का समय बचा सकता है


इसी से मेरा काम बना है। यह वास्तव में बच्चे को क्लिक इवेंट भेजने के लिए पूरे माता-पिता को बनाता है। इसका प्रत्यक्ष माता-पिता होना भी आवश्यक नहीं है (माता-पिता का अभिभावक हो सकता है)।
— Android डेवलपर

यदि आप एक प्रतिनिधि के लिए एक दृश्य है तो यह संभवत: काम करता है। क्या होगा यदि आपके पास, स्पर्श क्षेत्र को बढ़ाने के लिए 50 विचार हैं? - इस स्क्रीनशॉट में जैसे: plus.google.com/u/0/b/112127498414857833804/… - क्या एक टचडेलगेट तब भी एक उपयुक्त समाधान है?
— मार्टिन

2

@ मेसन ली की टिप्पणी के अनुसार, इससे मेरी समस्या हल हो गई। मेरी परियोजना में सापेक्ष लेआउट और एक बटन था। तो जनक है -> लेआउट और बच्चा है -> एक बटन।

यहाँ एक गूगल लिंक उदाहरण गूगल कोड है

उनके बहुत मूल्यवान उत्तर को हटाने के मामले में मैंने उनका जवाब यहाँ दिया।

मुझे हाल ही में टचडेलगेट का उपयोग करने के तरीके के बारे में पूछा गया था। मैं इस पर थोड़ा कठोर था और मुझे इस पर कोई अच्छा दस्तावेज नहीं मिला। यहाँ कोड मैंने थोड़े परीक्षण और त्रुटि के बाद लिखा है। Touch_delegate_view आईडी touch_delegate_root के साथ एक साधारण सा संबंध है। मैंने एक एकल, लेआउट के बच्चे के साथ परिभाषित किया, बटन प्रतिनिधि_बटन। इस उदाहरण में मैं बटन के क्लिक करने योग्य क्षेत्र को अपने बटन के ऊपर 200 पिक्सेल तक बढ़ाता हूं।

public class TouchDelegateSample extends Activity {

  Button mButton;   
  @Override   
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.touch_delegate_view);
    mButton = (Button)findViewById(R.id.delegated_button);
    View parent = findViewById(R.id.touch_delegate_root);

    // post a runnable to the parent view's message queue so its run after
    // the view is drawn
    parent.post(new Runnable() {
      @Override
      public void run() {
        Rect delegateArea = new Rect();
        Button delegate = TouchDelegateSample.this.mButton;
        delegate.getHitRect(delegateArea);
        delegateArea.top -= 200;
        TouchDelegate expandedArea = new TouchDelegate(delegateArea, delegate);
        // give the delegate to an ancestor of the view we're delegating the
        // area to
        if (View.class.isInstance(delegate.getParent())) {
          ((View)delegate.getParent()).setTouchDelegate(expandedArea);
        }
      }
    });   
  } 
}

चीयर्स, जस्टिन एंड्रॉइड टीम @ गूगल

मुझसे कुछ शब्द: यदि आप बाईं ओर का विस्तार करना चाहते हैं, तो आप ऋण के साथ मान देते हैं, और यदि आप ऑब्जेक्ट के दाईं ओर का विस्तार चाहते हैं, तो आप प्लस के साथ मूल्य देते हैं। यह ऊपर और नीचे के साथ समान काम करता है।


यहां जादू का संकेत एक बटन लगता है - किसी तरह मुझे लगता है कि टचडेलगेट कई बटन के लिए अनुपयोगी है। क्या आप इसकी पुष्टि कर सकते हैं?
— मार्टिन

1

क्या यह उस विशेष घटक (बटन) को पैडिंग देने का बेहतर विचार नहीं है।


1
यह बड़ा देखने के लिए करना होगा। क्या होगा यदि आपके पास एक बटन के ऊपर कुछ गैर क्लिकबेब पाठ पाठ है और आप चाहते हैं कि बटन के लिए क्लिक सटीकता को बेहतर बनाने के लिए उस पाठ के क्षेत्र का उपयोग किया जाए। - इस स्क्रीनशॉट की तरह: plus.google.com/u/0/b/112127498414857833804/…
— मार्टिन

1

पार्टी के लिए थोड़ा देर से, लेकिन बहुत शोध के बाद, मैं अब उपयोग कर रहा हूं:

/**
 * Expand the given child View's touchable area by the given padding, by
 * setting a TouchDelegate on the given ancestor View whenever its layout
 * changes.
 */*emphasized text*
public static void expandTouchArea(final View ancestorView,
    final View childView, final Rect padding) {

    ancestorView.getViewTreeObserver().addOnGlobalLayoutListener(
        new OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                TouchDelegate delegate = null;

                if (childView.isShown()) {
                    // Get hitRect in parent's coordinates
                    Rect hitRect = new Rect();
                    childView.getHitRect(hitRect);

                    // Translate to ancestor's coordinates
                    int ancestorLoc[] = new int[2];
                    ancestorView.getLocationInWindow(ancestorLoc);

                    int parentLoc[] = new int[2];
                    ((View)childView.getParent()).getLocationInWindow(
                        parentLoc);

                    int xOffset = parentLoc[0] - ancestorLoc[0];
                    hitRect.left += xOffset;
                    hitRect.right += xOffset;

                    int yOffset = parentLoc[1] - ancestorLoc[1];
                    hitRect.top += yOffset;
                    hitRect.bottom += yOffset;

                    // Add padding
                    hitRect.top -= padding.top;
                    hitRect.bottom += padding.bottom;
                    hitRect.left -= padding.left;
                    hitRect.right += padding.right;

                    delegate = new TouchDelegate(hitRect, childView);
                }

                ancestorView.setTouchDelegate(delegate);
            }
        });
}

यह स्वीकृत समाधान से बेहतर है क्योंकि यह किसी भी पूर्वज व्यू पर टचडेलगेट सेट करने की अनुमति देता है, न कि केवल पैरेंट व्यू।

स्वीकृत समाधान के विपरीत, जब भी पूर्वज व्यू के लेआउट में कोई परिवर्तन होता है, तो यह टचडेलगेट को भी अपडेट करता है।


0

यदि आप इसे प्रोग्रामिक रूप से नहीं करना चाहते हैं, तो बस इमेज के आसपास पारदर्शी क्षेत्र बनाएं, यदि आप बटन के लिए पृष्ठभूमि के रूप में छवि का उपयोग कर रहे हैं (देखें)।

स्पर्श क्षेत्र को बढ़ाने के लिए ग्रे क्षेत्र पारदर्शी हो सकता है।

यहाँ छवि विवरण दर्ज करें


1
क्या तब आसपास खाली जगह नहीं बनेगी जो देखने के लिए किसी और चीज के लिए इस्तेमाल नहीं की जा सकती है? यदि आप सूचना बटन को एक बटन बंद करना चाहते हैं और बटन क्लिक क्षेत्र को बढ़ाने के लिए पाठ क्षेत्र का उपयोग करना चाहते हैं तो क्या होगा?
— मार्टिन

मैं इसका सबसे अच्छा और अंतिम तरीका नहीं कहता। लेकिन यह कई परिदृश्यों में फिट होगा जहां आप एक छोटी बटन छवि दिखाना चाहते हैं लेकिन स्पर्श क्षेत्र को बढ़ाया जाना चाहिए। आपके मामले में जब आप अन्य विचारों (टेक्स्टव्यू) पर क्लिक करते हैं, तो बटन को पूर्वता देना मुश्किल होता है, यह सब एक साथ होना अलग चुनौती है।
— विनायक बेविनकत्ती

0

ज्यादातर मामलों में, आप उस दृश्य को रैप कर सकते हैं जिसके लिए किसी अन्य हेडलेस व्यू (कृत्रिम पारदर्शी दृश्य) में बड़े स्पर्श क्षेत्र की आवश्यकता होती है और आवरण दृश्य में पैडिंग / मार्जिन जोड़ते हैं और मूल दृश्य के बजाय आवरण दृश्य को भी क्लिक / टच देते हैं एक बड़ा स्पर्श क्षेत्र है।


क्या तब आसपास खाली जगह नहीं बनेगी जो देखने के लिए किसी और चीज के लिए इस्तेमाल नहीं की जा सकती है? यदि आप सूचना बटन को एक बटन बंद करना चाहते हैं और बटन क्लिक क्षेत्र को बढ़ाने के लिए पाठ क्षेत्र का उपयोग करना चाहते हैं तो क्या होगा?
— मार्टिन

@ मॉर्टिन, यह निर्भर करता है कि आप इसे कैसे करते हैं। और जो कुछ भी आप चाहते हैं उसे करना आसान होना चाहिए - इन सभी विचारों के शीर्ष पर एक पारदर्शी दृश्य में जो कुछ भी आप चाहते हैं (बस कई दृश्य जो आप चाहते हैं) लपेटें और उस क्षेत्र पर भी एक क्लिक असाइन करें।
— पूर्णांक

0

बहुत कम प्रतिबंधों के साथ उदारता से स्पर्श क्षेत्र का विस्तार करने के लिए निम्नलिखित कोड का उपयोग करें।

यह आपको पिक्सेल में दिए viewगए ancestorदृश्य के भीतर दिए गए स्पर्श क्षेत्र का विस्तार करने देता है expansion। जब तक दिया गया दृश्य पूर्वजों के लेआउट ट्री में है, तब तक आप किसी भी पूर्वज को चुन सकते हैं।

    public static void expandTouchArea(final View view, final ViewGroup ancestor, final int expansion) {
    ancestor.post(new Runnable() {
        public void run() {
            Rect bounds = getRelativeBounds(view, ancestor);
            Rect expandedBounds = expand(bounds, expansion);
            // LOG.debug("Expanding touch area of {} within {} from {} by {}px to {}", view, ancestor, bounds, expansion, expandedBounds);
            ancestor.setTouchDelegate(new TouchDelegate(expandedBounds, view));
        }

        private Rect getRelativeBounds(View view, ViewGroup ancestor) {
            Point relativeLocation = getRelativeLocation(view, ancestor);
            return new Rect(relativeLocation.x, relativeLocation.y,
                            relativeLocation.x + view.getWidth(),
                            relativeLocation.y + view.getHeight());
        }

        private Point getRelativeLocation(View view, ViewGroup ancestor) {
            Point absoluteAncestorLocation = getAbsoluteLocation(ancestor);
            Point absoluteViewLocation = getAbsoluteLocation(view);
            return new Point(absoluteViewLocation.x - absoluteAncestorLocation.x,
                             absoluteViewLocation.y - absoluteAncestorLocation.y);
        }

        private Point getAbsoluteLocation(View view) {
            int[] absoluteLocation = new int[2];
            view.getLocationOnScreen(absoluteLocation);
            return new Point(absoluteLocation[0], absoluteLocation[1]);
        }

        private Rect expand(Rect rect, int by) {
            Rect expandedRect = new Rect(rect);
            expandedRect.left -= by;
            expandedRect.top -= by;
            expandedRect.right += by;
            expandedRect.bottom += by;
            return expandedRect;
        }
    });
}

लागू होने वाले प्रतिबंध:

  • स्पर्श क्षेत्र दृश्य के पूर्वज की सीमा से अधिक नहीं हो सकता है क्योंकि पूर्वज को स्पर्श घटना को देखने के लिए अग्रेषित करने में सक्षम होना चाहिए।
  • केवल एक TouchDelegateको सेट किया जा सकता है ViewGroup। यदि आप कई टच डेलिगेट्स के साथ काम करना चाहते हैं, तो विभिन्न पूर्वजों का चयन करें या कंपोज़िंग टच डेलिगेट का उपयोग करें जैसे कि कैसे कई टचडेलगेट का उपयोग करें ।

0

क्योंकि मुझे टचडेलगेट की आयत का नया आकार प्राप्त करने के लिए लेआउट पास की प्रतीक्षा करने का विचार पसंद नहीं आया, इसलिए मैं एक अलग समाधान के लिए गया:

public class TouchSizeIncreaser extends FrameLayout {
    public TouchSizeIncreaser(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        return true;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        final View child = getChildAt(0);
        if(child != null) {
            child.onTouchEvent(event);
        }
        return true;
    }
}

और फिर, एक लेआउट में:

<ch.tutti.ui.util.TouchSizeIncreaser
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="10dp">

    <Spinner
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"/>
</ch.tutti.ui.util.TouchSizeIncreaser>

विचार यह है कि TouchSizeIncreaser FrameLayout स्पिनर को लपेट देगा (किसी भी बच्चे को देख सकता है) और आगे की सभी कैप्चर की गई घटनाओं को इसमें शामिल किया गया है, जिससे बच्चे को देखने में मदद मिलेगी। यह क्लिक के लिए काम करता है, स्पिनर खुलता है भले ही इसकी सीमा के बाहर क्लिक किया गया हो, यह सुनिश्चित नहीं है कि अन्य अधिक जटिल मामलों के लिए क्या निहितार्थ हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.