iOS - आगे सभी एक दृश्य के माध्यम से छूता है


141

मेरे पास कई अन्य दृश्यों के ऊपर एक दृश्य है। मैं केवल स्क्रीन पर कुछ संख्याओं के स्पर्श का पता लगाने के लिए ओवरली का उपयोग कर रहा हूं, लेकिन इसके अलावा मैं यह नहीं चाहता कि दृश्य नीचे के अन्य विचारों के व्यवहार को रोकें, जो कि स्क्रॉलव्यू आदि हैं। मैं कैसे सभी स्पर्शों को आगे बढ़ा सकता हूं। यह ओवरले दृश्य? यह UIView का एक उप-समूह है।


2
क्या आपने अपनी समस्या हल कर ली है? यदि हाँ, तो कृपया उत्तर स्वीकार करें ताकि इसका समाधान खोजने में अन्य लोगों को आसानी हो क्योंकि मैं उसी मुद्दे का सामना कर रहा हूं।
खुशबु देसाई

इस जवाब अच्छा काम करता है stackoverflow.com/a/4010809/4833705
लांस सामरिया

जवाबों:


121

उपयोगकर्ता इंटरैक्शन को अक्षम करना मेरी सभी आवश्यकता थी!

उद्देश्य सी:

myWebView.userInteractionEnabled = NO;

स्विफ्ट:

myWebView.isUserInteractionEnabled = false

यह मेरी स्थिति में काम करता है जहां मेरे पास बटन का एक उपक्षेत्र था। मैंने सबव्यू और बटन पर बातचीत को अक्षम कर दिया।
simple_code

2
स्विफ्ट 4 में,myWebView.isUserInteractionEnabled = false
लुई 'लेरो' ड्यूपॉन्ट

117

ओवरले दृश्य से नीचे के विचारों को छूने के लिए, UIView में निम्न विधि को लागू करें:

उद्देश्य सी:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    NSLog(@"Passing all touches to the next view (if any), in the view stack.");
    return NO;
}

स्विफ्ट 5:

override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
    print("Passing all touches to the next view (if any), in the view stack.")
    return false
}

3
मेरे पास एक ही मुद्दा है, लेकिन मैं जो चाहता हूं, अगर मैं इशारे के साथ ज़ूम / रोटेट / मूविंग व्यू कर रहा हूं तो इसे हां लौटना चाहिए और बाकी इवेंट के लिए इसे वापस लौटना चाहिए, मैं इसे कैसे हासिल कर सकता हूं?
मिनाक्षी

@ मिनाक्षी एक बिल्कुल अलग सवाल है, उसके लिए एक नया सवाल पूछिए।
फेटी

लेकिन इस सरल दृष्टिकोण के बारे में पता होना चाहिए आप सवाल में परत के शीर्ष पर बटन और इतने पर नहीं है!
fattie

56

यह एक पुराना धागा है, लेकिन यह एक खोज पर आया है, इसलिए मैंने सोचा कि मैं अपना 2 सी जोड़ दूंगा। मेरे पास उपविषयों के साथ एक कवर UIView है, और केवल एक साक्षात्कार में आने वाले स्पर्श को रोकना चाहते हैं, इसलिए मैंने PixelCloudSt के उत्तर को संशोधित किया

-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    for (UIView* subview in self.subviews ) {
        if ( [subview hitTest:[self convertPoint:point toView:subview] withEvent:event] != nil ) {
            return YES;
        }
    }
    return NO;
}

1
आपको एक कस्टम UIView उपवर्ग (या किसी अन्य UIView उपवर्ग का एक उपवर्ग जैसे कि UIImageView या जो भी हो) बनाने और इस फ़ंक्शन को ओवरराइड करने की आवश्यकता है। संक्षेप में, उपवर्ग में .h फ़ाइल में पूरी तरह से खाली '@interface' हो सकता है, और ऊपर दिया गया कार्य '@ कार्यान्वयन' की संपूर्ण सामग्री हो सकता है।
fresidue

धन्यवाद, यह वही है जो मुझे अपने UIVIV के खाली स्थान के माध्यम से छूने के लिए पारित करने की आवश्यकता थी, जिसे पीछे देखने के द्वारा नियंत्रित किया जा सकता है। +100
डैनी

40

@Fresidue उत्तर का उन्नत संस्करण। आप इस UIViewउपवर्ग का उपयोग पारदर्शी दृश्य पासिंग टच के रूप में कर सकते हैं । उद्देश्य-सी में कार्यान्वयन :

@interface PassthroughView : UIView

@end

@implementation PassthroughView

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    for (UIView *view in self.subviews) {
        if (!view.hidden && [view pointInside:[self convertPoint:point toView:view] withEvent:event]) {
            return YES;
        }
    }
    return NO;
}

@end

और स्विफ्ट में:

class PassthroughView: UIView {
  override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
    return subviews.contains(where: {
      !$0.isHidden
      && $0.isUserInteractionEnabled
      && $0.point(inside: self.convert(point, to: $0), with: event)
    })
  }
}

सुझाव:

फिर कहें कि आपके पास एक बड़ा "धारक" पैनल है, शायद पीछे एक टेबल व्यू के साथ। आप "धारक" पैनल बनाते हैं PassthroughView। अब यह काम करेगा, आप "धारक" के माध्यम से तालिका को स्क्रॉल कर सकते हैं।

परंतु!

  1. "धारक" पैनल के शीर्ष पर आपके पास कुछ लेबल या आइकन हैं। मत भूलना, निश्चित रूप से उन लोगों को चिह्नित किया जाना चाहिए जो उपयोगकर्ता सहभागिता को सक्षम करते हैं!

  2. "धारक" पैनल के शीर्ष पर आपके पास कुछ बटन हैं। मत भूलो, निश्चित रूप से उन लोगों को चिह्नित किया जाना चाहिए जो उपयोगकर्ता की सहभागिता को सक्षम करते हैं!

  3. नोट कुछ हद तक भी संदेहास्पद "धारक" खुद कि - दृश्य आप उपयोग PassthroughViewपर - चिह्नित किया जाना चाहिए उपयोगकर्ता बातचीत सक्षम पर ! यही पर है !! (अन्यथा, PassthroughView में कोड को कभी नहीं बुलाया जाएगा।)


1
मैंने स्विफ्ट के लिए दिए गए समाधान का उपयोग किया है। यह ios 11 पर काम कर रहा है लेकिन iOS 10 पर हर बार क्रैश हो रहा है। बैड एक्सेस दिखा रहा है। कोई उपाय?
सौमेन

आपने मेरे दिनों को बचाया, इसने नीचे के उविवि को छूने के लिए काम किया।
आओइ

1
भूल भी जांच करने के लिए नहीं है$0.isUserInteractionEnabled
शॉन Thielen

7

मेरे पास UIStackView के साथ एक समान मुद्दा था (लेकिन कोई अन्य दृश्य हो सकता है)। मेरा विन्यास निम्नलिखित था: कन्टेनर व्यू और स्टैक व्यू के साथ कंट्रोलर देखें

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

मैंने जो कुछ किया वह सबव्यू को परिभाषित करने वाली संपत्ति के साथ UIStackView का एक उपवर्ग बनाता है जो कि स्पर्श करने योग्य होना चाहिए। अब, साइड बटन पर कोई भी टच (* viewsWithActiveTouch * एरे में शामिल) बटन को दिया जाएगा, जबकि इन व्यूज के अलावा स्टैकव्यू पर किसी भी टच को इंटरसेप्ट नहीं किया जाएगा, और इसलिए स्टैक के नीचे जो भी है उसे पास कर दिया जाएगा राय।

/** Subclass of UIStackView that does not accept touches, except for specific subviews given in the viewsWithActiveTouch array */
class NoTouchStackView: UIStackView {

  var viewsWithActiveTouch: [UIView]?

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

    if let activeViews = viewsWithActiveTouch {
        for view in activeViews {
           if CGRectContainsPoint(view.frame, point) {
                return view

           }
        }
     }
     return nil
   }
}

6

यदि आप जिस टच को फ़ॉरवर्ड करना चाहते हैं, वह सबव्यू / सुपरवाइवे नहीं होता है, तो आप अपने यूआईईवीई सबक्लास में एक कस्टम प्रॉपर्टी सेट कर सकते हैं जैसे:

@interface SomeViewSubclass : UIView {

    id forwardableTouchee;

}
@property (retain) id forwardableTouchee;

इसे अपने .m में संश्लेषित करना सुनिश्चित करें:

@synthesize forwardableTouchee;

और फिर अपने किसी भी UIResponder विधियों में निम्नलिखित को शामिल करें जैसे:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    [self.forwardableTouchee touchesBegan:touches withEvent:event];

}

जहाँ भी आप अपने यूआईवीवाई को इंस्टेंट करते हैं, फॉरवर्ड करने योग्य संपत्ति सेट करें, जो भी आप चाहते हैं कि घटनाओं को आगे बढ़ाया जाए:

    SomeViewSubclass *view = [[[SomeViewSubclass alloc] initWithFrame:someRect] autorelease];
    view.forwardableTouchee = someOtherView;

4

स्विफ्ट 5 में

class ThroughView: UIView {
    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        guard let slideView = subviews.first else {
            return false
        }

        return slideView.hitTest(convert(point, to: slideView), with: event) != nil
    }
}

4

मुझे UIStackView के माध्यम से टच पास करने की आवश्यकता थी। अंदर एक UIView पारदर्शी था, लेकिन UIStackView ने सभी स्पर्शों का उपभोग किया। यह मेरे लिए काम किया:

class PassThrouStackView: UIStackView {

    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        let view = super.hitTest(point, with: event)
        if view == self {
            return nil
        }
        return view
    }
}

सभी व्‍यवस्‍थित व्‍यवस्‍थाएं अभी भी स्‍पर्श प्राप्‍त करती हैं, लेकिन UIStackView पर स्‍पर्श खुद नीचे के दृश्य (मेरे लिए एक मानचित्र दृश्य) के माध्यम से हुआ।


2

यहां तक ​​कि लगता है कि आप इसके बहुत से जवाब यहां भी दे रहे हैं, जो तेजी से साफ है, जिसकी मुझे जरूरत नहीं है। इसलिए मैंने यहाँ @fresidue से उत्तर लिया और इसे तेजी से परिवर्तित किया क्योंकि यह अब ज्यादातर डेवलपर्स यहाँ उपयोग करना चाहते हैं।

इसने मेरी समस्या को हल कर दिया जहां मेरे पास बटन के साथ कुछ पारदर्शी टूलबार हैं लेकिन मैं चाहता हूं कि टूलबार उपयोगकर्ता के लिए अदृश्य हो और घटनाओं को स्पर्श करना चाहिए।

isUserInteractionEnabled = false जैसा कि कुछ कहा गया है, मेरे परीक्षण पर आधारित विकल्प नहीं है।

 override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
    for subview in subviews {
        if subview.hitTest(convert(point, to: subview), with: event) != nil {
            return true
        }
    }
    return false
}

1

मेरे पास StackView के अंदर कुछ लेबल थे और मुझे ऊपर दिए गए समाधानों से अधिक सफलता नहीं मिली, इसके बजाय मैंने नीचे दिए गए कोड का उपयोग करके अपनी समस्या हल की:

    let item = ResponsiveLabel()

    // Configure label

    stackView.addArrangedSubview(item)

सबकास्टिंग UIStackView:

class PassThrouStackView:UIStackView{
    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        for subview in self.arrangedSubviews {
            let convertedPoint = convert(point, to: subview)
            let labelPoint = subview.point(inside: convertedPoint, with: event)
            if (labelPoint){
                return subview
            }

        }
        return nil
    }

}

तब आप कुछ ऐसा कर सकते थे:

class ResponsiveLabel:UILabel{
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        // Respond to touch
    }
}

0

कुछ इस तरह से आजमाएं ...

for (UIView *view in subviews)
  [view touchesBegan:touches withEvent:event];

ऊपर दिए गए कोड, आपके टचबैन विधि में उदाहरण के लिए टच को देखने के सभी साक्षात्कारों को पास करेंगे।


6
इस दृष्टिकोण के साथ समस्या AFAIK है कि आगे UIKit ढांचे के वर्गों को छूने का प्रयास सबसे अधिक बार कोई प्रभाव नहीं होगा। Apple के प्रलेखन के अनुसार UIKit फ्रेमवर्क वर्गों को उन स्पर्शों को प्राप्त करने के लिए डिज़ाइन नहीं किया गया है जिनके पास कुछ अन्य दृश्य के लिए दृश्य गुण सेट है। इसलिए यह दृष्टिकोण ज्यादातर यूआईवीवाई के कस्टम उपवर्गों के लिए काम करता है।
23

0

स्थिति मैं करने की कोशिश कर रहा था नेस्टेड UIStackView के अंदर नियंत्रण का उपयोग करके एक नियंत्रण कक्ष का निर्माण किया गया था। कुछ नियंत्रणों में UIBextField के अन्य UIButton के साथ थे। इसके अलावा, नियंत्रणों की पहचान करने के लिए लेबल भी थे। मैं जो करना चाहता था, उसे कंट्रोल पैनल के पीछे एक बड़ा "अदृश्य" बटन लगा दिया गया था, ताकि यदि कोई उपयोगकर्ता बटन या टेक्स्ट फ़ील्ड के बाहर किसी क्षेत्र पर टैप करता है, तो मैं उसे पकड़ सकता हूं और कार्रवाई कर सकता हूं - मुख्य रूप से किसी कीबोर्ड को खारिज कर सकता है यदि कोई पाठ फ़ील्ड सक्रिय था (resignFirstResponder)। हालांकि, नियंत्रण कक्ष में एक लेबल या अन्य रिक्त क्षेत्र पर टैप करने से चीजें गुजरती नहीं हैं। उपरोक्त चर्चाएँ नीचे मेरे उत्तर के साथ आने में सहायक थीं।

मूल रूप से, मैंने UIStackView को उप-वर्गीकृत किया और नियंत्रण के प्रकार की तलाश करने के लिए "बिंदु (अंदर: साथ) दिनचर्या को ओवरवोट किया, जिसे स्पर्श की आवश्यकता थी और लेबल की तरह" अनदेखा "चीजों को जिन्हें मैं अनदेखा करना चाहता था। यह UIStackView के अंदर के लिए भी जाँच करता है ताकि चीजें नियंत्रण कक्ष संरचना में पुनरावृत्ति कर सकें।

कोड शायद थोड़ा अधिक क्रिया है जितना कि यह होना चाहिए। लेकिन यह डिबगिंग में सहायक था और उम्मीद है कि दिनचर्या क्या कर रही है में अधिक स्पष्टता प्रदान करती है। UIStackView की PassThruStack के वर्ग को बदलने के लिए बस इंटरफ़ेस बिल्डर में सुनिश्चित करें।

class PassThruStack: UIStackView {

override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {

    for view in self.subviews {
        if !view.isHidden {
            let isStack = view is UIStackView
            let isButton = view is UIButton
            let isText = view is UITextField
            if isStack || isButton || isText {
                let pointInside = view.point(inside: self.convert(point, to: view), with: event)
                if pointInside {
                    return true
                }
            }
        }
    }
    return false
}

}


-1

जैसा कि @PixelCloudStv ने सुझाव दिया है कि अगर आप एक दृश्य से दूसरे दृश्य को छूना चाहते हैं, लेकिन इस प्रक्रिया पर कुछ अतिरिक्त नियंत्रण के साथ - उपवर्ग UIView

// हैडर

@interface TouchView : UIView

@property (assign, nonatomic) CGRect activeRect;

@end

// कार्यान्वयन

#import "TouchView.h"

@implementation TouchView

#pragma mark - Ovverride

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    BOOL moveTouch = YES;
    if (CGRectContainsPoint(self.activeRect, point)) {
        moveTouch = NO;
    }
    return moveTouch;
}

@end

InterfaceBuilder के बाद बस ViewView को TouchView के वर्ग में सेट करें और अपनी आयत के साथ सक्रिय आयत सेट करें। साथ ही यू अन्य लॉजिक को बदल और कार्यान्वित कर सकता है।

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