UIView की सीमा से परे सहभागिता


92

क्या UIButton (या उस मामले के लिए कोई अन्य नियंत्रण) के लिए स्पर्श की घटनाओं को प्राप्त करना संभव है जब UIButton का फ्रेम माता-पिता के फ्रेम के बाहर होता है? जब मैं ऐसा करने की कोशिश करता हूं, तो ऐसा लगता है कि मेरा UIButton किसी भी कार्यक्रम को प्राप्त करने में सक्षम नहीं है। मैं इसके आसपास कैसे काम करूं?


1
यह मेरे लिए पूरी तरह से काम करता है। developer.apple.com/library/ios/qa/qa2013/qa1812.html सर्वश्रेष्ठ
फ्रैंक ली

2
यह भी अच्छा और प्रासंगिक है (या शायद एक
डुबकी

जवाबों:


93

हाँ। आप hitTest:withEvent:उस दृश्य की तुलना में बड़े सेट के लिए किसी दृश्य को वापस करने की विधि को ओवरराइड कर सकते हैं । UIView क्लास संदर्भ देखें ।

संपादित करें: उदाहरण:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    CGFloat radius = 100.0;
    CGRect frame = CGRectMake(-radius, -radius,
                              self.frame.size.width + radius,
                              self.frame.size.height + radius);

    if (CGRectContainsPoint(frame, point)) {
        return self;
    }
    return nil;
}

संपादित करें 2: (स्पष्टीकरण के बाद :) यह सुनिश्चित करने के लिए कि बटन को माता-पिता की सीमा के भीतर माना जाता है, आपको pointInside:withEvent:बटन के फ्रेम को शामिल करने के लिए माता-पिता में ओवरराइड करने की आवश्यकता है ।

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    if (CGRectContainsPoint(self.view.bounds, point) ||
        CGRectContainsPoint(button.view.frame, point))
    {
        return YES;
    }
    return NO;
}

ओवरराइडिंग पॉइंट के लिए कोड को नोट करें। उल्टा यह बहुत सही नहीं है। जैसा कि समन नीचे बताते हैं, यह करें:

-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
    {
    if ( CGRectContainsPoint(self.oversizeButton.frame, point) )
        return YES;

    return [super pointInside:point withEvent:event];
    }

ध्यान दें कि आप self.oversizeButtonइस UIView उपवर्ग में एक IBOutlet के रूप में बहुत संभावना रखते हैं ; तब आप प्रश्न में "ओवरसाइज़ बटन" को खींच सकते हैं, प्रश्न में विशेष दृश्य। (या, यदि किसी कारण से आप इस परियोजना में बहुत कुछ कर रहे थे, तो आपके पास एक विशेष UIButton उपवर्ग होगा, और आप उन वर्गों के लिए अपनी उप-सूची सूची के माध्यम से देख सकते हैं।) आशा है कि यह मदद करता है।


क्या आप कुछ नमूना कोड के साथ इसे सही तरीके से लागू करने में मेरी मदद कर सकते हैं? इसके अलावा, मैंने संदर्भ पढ़ा और निम्नलिखित पंक्ति के कारण, मैं उलझन में हूं: "रिसीवर के सीमा के बाहर स्थित बिंदुओं को कभी भी हिट के रूप में रिपोर्ट नहीं किया जाता है, भले ही वे वास्तव में रिसीवर के किसी एक साक्षात्कार के भीतर झूठ बोलते हों। साक्षात्कार दृष्टिगत रूप से सीमाओं से परे हो सकते हैं। यदि उनके माता-पिता की क्लिप को देखा जाए तो उनके माता-पिता की संपत्ति पर कोई प्रतिबंध नहीं लगाया जाता है। हालांकि, हिट परीक्षण हमेशा माता-पिता की सीमा के बाहर के बिंदुओं की अनदेखी करता है। "
थॉमस एमआर

यह विशेष रूप से यह हिस्सा है जो ऐसा प्रतीत होता है जैसे कि यह वह समाधान नहीं है जिसकी मुझे आवश्यकता है: "हालांकि, हिट परीक्षण हमेशा माता-पिता के दृष्टिकोण के बाहर के बिंदुओं की उपेक्षा करता है" .. लेकिन मैं गलत तरीके से संभोग कर सकता हूं, मुझे लगता है कि ऐप्पल संदर्भ कभी-कभी वास्तव में भ्रमित करते हैं ..
थॉमसएम

आह, मैं अब समझ गया। pointInside:withEvent:बटन के फ्रेम को शामिल करने के लिए आपको माता-पिता को ओवरराइड करने की आवश्यकता है । मैं ऊपर अपने उत्तर में कुछ नमूना कोड जोड़ूंगा।
14

क्या UIView के तरीकों को ओवरराइड किए बिना ऐसा करने का एक तरीका है? उदाहरण के लिए, यदि आपके विचार पूरी तरह से UIKit के लिए सामान्य हैं और एक Nib के माध्यम से आरंभ किए गए हैं, तो क्या आप इन तरीकों को अपने UIViewController के भीतर से ओवरराइड कर सकते हैं?
RLH

1
hitTest:withEvent:और pointInside:withEvent:क्षेत्र को मेरे लिए नहीं बुलाया जाता है जब मैं एक बटन पर दबाता हूं जो माता-पिता की सीमा के बाहर स्थित है। क्या गलत हो सकता है?
.सुदेउद

24

@jnic, मैं iOS SDK 5.0 पर काम कर रहा हूं और आपके कोड को सही तरीके से काम करने के लिए मुझे ऐसा करना पड़ा:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
if (CGRectContainsPoint(button.frame, point)) {
    return YES;
}
return [super pointInside:point withEvent:event]; }

मेरे मामले में कंटेनर दृश्य एक UIButton है और सभी बाल तत्व भी UIButtons हैं जो मूल UIButton की सीमा से बाहर जा सकते हैं।

श्रेष्ठ


20

माता-पिता के विचार में आप हिट परीक्षा पद्धति को ओवरराइड कर सकते हैं:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    CGPoint translatedPoint = [_myButton convertPoint:point fromView:self];

    if (CGRectContainsPoint(_myButton.bounds, translatedPoint)) {
        return [_myButton hitTest:translatedPoint withEvent:event];
    }
    return [super hitTest:point withEvent:event];

}

इस स्थिति में, यदि बिंदु आपके बटन की सीमा में आता है, तो आप वहां कॉल को अग्रेषित करते हैं; यदि नहीं, तो मूल कार्यान्वयन पर वापस लौटें।


17

मेरे मामले में, मेरे पास एक UICollectionViewCellउपवर्ग था जिसमें एक था UIButton। मैं clipsToBoundsसेल पर अक्षम हो गया और बटन सेल की सीमा के बाहर दिखाई दे रहा था। हालाँकि, बटन स्पर्श घटनाओं को प्राप्त नहीं कर रहा था। मैं जैक के उत्तर का उपयोग करके बटन पर स्पर्श की घटनाओं का पता लगाने में सक्षम था: https://stackoverflow.com/a/30431157/3744977

यहाँ एक स्विफ्ट संस्करण है:

override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {

    let translatedPoint = button.convertPoint(point, fromView: self)

    if (CGRectContainsPoint(button.bounds, translatedPoint)) {
        print("Your button was pressed")
        return button.hitTest(translatedPoint, withEvent: event)
    }
    return super.hitTest(point, withEvent: event)
}

स्विफ्ट 4:

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {

    let translatedPoint = button.convert(point, from: self)

    if (button.bounds.contains(translatedPoint)) {
        print("Your button was pressed")
        return button.hitTest(translatedPoint, with: event)
    }
    return super.hitTest(point, with: event)
}

यह वास्तव में मेरा परिदृश्य था। दूसरी बात यह है कि आपको यह तरीका कलेक्शन व्यू क्लास के अंदर रखना चाहिए।
हामिद रजा अंसारी

लेकिन आप बटन को ओवरराइड विधि से इंजेक्ट क्यों करेंगे ???
रोममेक्स

10

ऐसा क्यों हो रहा है?

ऐसा इसलिए होता है क्योंकि जब आपका सबव्यू आपके सुपरवाइज की सीमा के बाहर होता है, तो उस सबव्यू पर होने वाली घटनाओं को स्पर्श करें, जो कि सबव्यू उस सबव्यू में नहीं पहुंचेगा। हालांकि, यह होगा अपने superview को वितरित किया।

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

आपको क्या करने की आवश्यकता है?

जब आपके पर्यवेक्षक को ऊपर बताई गई टच ईवेंट प्राप्त होती है, तो आपको स्पष्ट रूप से UIKit को बताना होगा कि मेरा सबव्यू इस टच ईवेंट को प्राप्त करने वाला होना चाहिए।

कोड के बारे में क्या?

अपने पर्यवेक्षण में, कार्यान्वित करें func hitTest(_ point: CGPoint, with event: UIEvent?)

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        if isHidden || alpha == 0 || clipsToBounds { return super.hitTest(point, with: event) }
        // convert the point into subview's coordinate system
        let subviewPoint = self.convert(point, to: subview)
        // if the converted point lies in subview's bound, tell UIKit that subview should be the one that receives this event
        if !subview.isHidden && subview.bounds.contains(subviewPoint) { return subview }
        return super.hitTest(point, with: event)
    }

आकर्षक गोटिया: आपको "उच्चतम-छोटे सुपरवाइवे" पर जाना चाहिए

आपको "ऊपर" जाना होगा "उच्चतम" दृश्य पर जो समस्या का दृश्य बाहर है।

विशिष्ट उदाहरण:

मान लें कि आपके पास एक स्क्रीन S है, जिसमें कंटेनर दृश्य C. कंटेनर दृश्य-नियंत्रक का दृश्य V है (रिकॉल V, C के अंदर बैठेगा और समान आकार का होगा।) V का एक सबव्यू (शायद एक बटन) B. B समस्या है। दृश्य जो वास्तव में वी के बाहर है।

लेकिन ध्यान दें कि B, C के बाहर भी है।

इस उदाहरण में आपको समाधान override hitTestको वास्तव में C पर लागू करना है, V से नहीं । यदि आप इसे V पर लागू करते हैं - तो यह कुछ भी नहीं करता है।


4
इसके लिए शुक्रिया! मैंने इसी से उपजी एक समस्या पर घंटे-घंटे बिताए हैं। मैं वास्तव में इस पोस्ट करने के लिए आपके समय की सराहना करता हूं। :)
क्लेज

@ScottZhu: मैंने आपके जवाब में एक महत्वपूर्ण गोटिया जोड़ दी। बेशक, आपको मेरे अतिरिक्त को हटाने या बदलने के लिए स्वतंत्र महसूस करना चाहिए! एक बार फिर धन्यवाद!
फेटी

9

स्विफ्ट:

जहाँ targetView वह दृश्य है जिसे आप ईवेंट प्राप्त करना चाहते हैं (जो कि इसके मूल दृश्य के फ्रेम के बाहर पूरी तरह या आंशिक रूप से स्थित हो सकता है)।

override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
        let pointForTargetView: CGPoint = targetView.convertPoint(point, fromView: self)
        if CGRectContainsPoint(targetView.bounds, pointForTargetView) {
            return closeButton
        }
        return super.hitTest(point, withEvent: event)
}

5

मेरे लिए (दूसरों के लिए), उत्तर विधि को ओवरराइड नहीं करना था hitTest, बल्कि pointInsideविधि है। मुझे यह केवल दो स्थानों पर करना था।

द सुपरविवि यह वह दृष्टिकोण है कि अगर यह clipsToBoundsसच हो गया था, तो यह इस पूरी समस्या को गायब कर देगा। तो यहाँ UIViewस्विफ्ट 3 में मेरा सरल है:

class PromiscuousView : UIView {
    override func point(inside point: CGPoint,
               with event: UIEvent?) -> Bool {
        return true
    }
} 

सबव्यू आपका माइलेज अलग-अलग हो सकता है, लेकिन मेरे मामले में मुझे उस सब-वे के लिए pointInsideविधि को भी लिखना पड़ा, जिसने तय किया था कि टच सीमा से बाहर है। मेरा उद्देश्य में है, सी:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    WEPopoverController *controller = (id) self.delegate;
    if (self.takeHitsOutside) {
        return YES;
    } else {
        return [super pointInside:point withEvent:event];
    }
}

यह उत्तर (और इसी प्रश्न पर कुछ अन्य) आपकी समझ को साफ करने में मदद कर सकते हैं।


2

स्विफ्ट 4.1 अपडेट किया गया

उसी UIView में स्पर्श की घटनाओं को प्राप्त करने के लिए आपको बस ओवरराइड विधि का पालन करना होगा, यह UIView में टैप किए गए विशिष्ट दृश्य की पहचान करेगा जिसे बाध्य किया गया है

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    let pointforTargetview:CGPoint = self.convert(point, to: btnAngle)
    if  btnAngle.bounds.contains(pointforTargetview) {
        return  self
    }
    return super.hitTest(point, with: event)
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.