2011-01-05 15 views
13

मैं एक राय यह है कि पेजिंग के साथ एक UIScrollView सक्षम में लोड किया जाता के हिस्से के रूप में एक UISlider है। मैंने एक अप्रत्याशित व्यवहार देखा है। यदि उपयोगकर्ता स्लाइडर को जल्दी से उपयोग करने का प्रयास करता है (यानी दबाएं और स्थानांतरित करें) तो यह स्क्रॉल व्यू को "सक्रिय" करता है, जिससे पेज स्विच हो जाता है। हालांकि, यदि स्लाइडर "सक्रिय" के दूसरे भाग के लिए आपका प्रेस और होल्ड करें और फिर आप स्लाइडर मान समायोजित कर सकते हैं। यह व्यवहार अवांछनीय है।UISlider और UIScrollView

में लोड होने पर UISlider उत्तरदायी बनाने का सबसे अच्छा तरीका क्या है? मैंने एक "अवरोधक" दृश्य जोड़ने के बारे में सोचा है जो स्लाइडर के नीचे रखी गई स्पर्श घटनाओं को खाती है, लेकिन यह सुनिश्चित नहीं है कि यह इसके बारे में जाने का सबसे अच्छा तरीका है या नहीं।

उत्तर

3

अपने स्क्रॉल व्यू को अपने स्लाइडर द्वारा कब्जे वाले क्षेत्र पर स्पर्श करें (hitTest:withEvent: ओवरराइड करें, आपको UIScrollView को उप-वर्ग करने की आवश्यकता हो सकती है)। यदि कहा गया क्षेत्र पर एक स्पर्श पता चला है, तो स्लाइडर पर स्पर्श को तुरंत पास करने के लिए अपने स्क्रॉल व्यू को बताएं।

+0

धन्यवाद, इसके साथ समाप्त हो गया। हालांकि, एक और विषमता ... यह व्यवहार केवल सिम्युलेटर पर प्रकट होना प्रतीत होता था। एक बार जब मैं इसे डिवाइस पर मिला तो यह ठीक किए बिना ठीक काम करता था। – MarkPowell

+0

दिलचस्प, परीक्षण के लिए सिम्युलेटर पर भरोसा न करने का एक अन्य कारण ... – BoltClock

+2

FWIW, मैं सिम्युलेटर (आईओएस 6) और डिवाइस (आईओएस 5.1) दोनों पर बिल्कुल वही व्यवहार (मूल प्रश्न में वर्णित) देख रहा हूं। मुझे स्लाइडर खींचने से पहले एक पल टैप करना और पकड़ना है, अन्यथा मुझे इसके बजाय स्क्रॉल व्यू ड्रैग मिलता है। –

40

UIScrollView पक्ष पर एक हिट परीक्षण के लिए कोई आवश्यकता नहीं है। चूंकि देरी द्वारा ही निर्धारित की जाती है। कस्टम hitTest:withEvent: को उप-वर्गीकरण और कार्यान्वित करने में सहायता नहीं होगी क्योंकि यह अभी भी देरी से ट्रिगर है।

मैं इस के लिए एक सुरुचिपूर्ण समाधान के लिए घंटे की खोज के बाद से मैं Apple की iOS आवेदन स्विचर में खुद volumeslider अनुकरण करना चाहता था।

चाल:

yourScrollView.delaysContentTouches = NO; 

दुर्भाग्य से इस UISliders ट्रैक के साथ घटनाओं को निष्क्रिय है, इसलिए इस भाग के लिए अपने UIScrollView किसी भी touchevents क्योंकि वे स्लाइडर द्वारा पहले पकड़े जाते हैं ट्रिगर नहीं करेगा।

उन जो UISliders अंगूठे में हैं के अलावा अन्य touchevents पारित करने के लिए रेक्ट आप UISlider उपवर्ग और निम्नलिखित जोड़ने के लिए:

// get the location of the thumb 
- (CGRect)thumbRect 
{ 
    CGRect trackRect = [self trackRectForBounds:self.bounds]; 
    CGRect thumbRect = [self thumbRectForBounds:self.bounds 
            trackRect:trackRect 
             value:self.value]; 
    return thumbRect; 
} 

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event 
{ 
    CGRect thumbFrame = [self thumbRect]; 

     // check if the point is within the thumb 
    if (CGRectContainsPoint(thumbFrame, point)) 
    { 
     // if so trigger the method of the super class 
     NSLog(@"inside thumb"); 
     return [super hitTest:point withEvent:event]; 
    } 
    else 
    { 
     // if not just pass the event on to your superview 
     NSLog(@"outside thumb"); 
     return [[self superview] hitTest:point withEvent:event]; 
    } 
} 
+0

धन्यवाद सेबेस्टियन, यह वही है जो मैं ढूंढ रहा था! –

+0

आपका स्वागत है, एलेक्स। –

+0

मैं बिल्कुल वही चीज़ ढूंढ रहा था, धन्यवाद! –

0

आप UIScrollView उपवर्ग और विधि ओवरराइड - (BOOL)touchesShouldBegin:(NSSet *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view इस प्रकार कर सकते हैं:

- (BOOL)touchesShouldBegin:(NSSet *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view { 
    if ([view isKindOfClass:[UISlider class]]) { 
     UITouch *touch = [[event allTouches] anyObject]; 
     CGPoint location = [touch locationInView:view]; 
     CGRect thumbRect; 
     UISlider *mySlide = (UISlider*) view; 
     CGRect trackRect = [mySlide trackRectForBounds:mySlide.bounds]; 
     thumbRect = [mySlide thumbRectForBounds:mySlide.bounds trackRect:trackRect value:mySlide.value]; 
     if (CGRectContainsPoint(thumbRect, location)) 
      return YES; 
    } 
    return NO; 
} 

इसके अलावा scrollview के लिए yourScrollView.delaysContentTouches = NO; संपत्ति सेट करें।

1

एक ऑडियो प्लेयर मैं एक sliderView के साथ सटीक समस्या थी बनाते समय और यह एक scrollView में जोड़ा जाता है, और जब भी मैं sliderView, scrollView स्पर्श और sliderView के बजाय प्राप्त करने के लिए प्रयोग किया जाता है को छुआ, scrollView ले जाया गया। इससे बचने के लिए, मैं scrollView की srcolling अक्षम है जब उपयोगकर्ता sliderView छुआ और अन्यथा स्क्रॉल सक्षम है।

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { 

    UIView *result = [super hitTest:point withEvent:event] ; 
    if (result == sliderView) 
    { 
     scrollView.scrollEnabled = NO ; 
    } 
    else 
    { 
     scrollView.scrollEnabled = YES ; 
    } 

    return result ; 

} 
1

मेरे समस्या इस मुद्दे का सुपरसेट था - मैं UITableViewCells अंदर UISliders मिल गया है और पूरे UITableView एक UIScrollView के अंदर एक पेज है। स्लाइडर अन्य दो के साथ बातचीत पर विनाश को तोड़ रहे थे और सबक्लासिंग समाधान काम नहीं कर पाए। यहां मैं यह काम कर रहा हूं कि यह महान काम कर रहा है: स्लाइडर आगे बढ़ते समय अधिसूचनाएं भेजें और UITableView और UIScrollView अक्षम करें इस समय के दौरान स्क्रॉलिंग करें। नीचे दी गई तस्वीर में ध्यान दें: मेरे स्लाइडर्स क्षैतिज हैं, मेरा टेबलव्यू लंबवत है, और मेरे UIScrollView में क्षैतिज पृष्ठ हैं।

UISlider in a UITableView in a UIScrollView

UITableViewCell प्रोग्राम के रूप में रूप से बनाए गए स्लाइडर के लिए घटनाओं को चुनता है:

self.numberSlider = [[UISlider alloc] init]; 
[self.numberSlider addTarget:self action:@selector(sliderValueChanged:) forControlEvents:UIControlEventValueChanged]; 
[self.numberSlider addTarget:self action:@selector(sliderTouchDown:) forControlEvents:UIControlEventTouchDown]; 
[self.numberSlider addTarget:self action:@selector(sliderTouchUp:) forControlEvents:UIControlEventTouchUpInside]; 
[self.numberSlider addTarget:self action:@selector(sliderTouchUp:) forControlEvents:UIControlEventTouchUpOutside]; 

इस ट्यूटोरियल के प्रयोजनों के लिए, हम केवल टचडाउन और ऊपर के बारे में परवाह:

- (void)sliderTouchDown:(UISlider *)sender 
{ 
    [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFY_SLIDER_TOUCH_BEGAN object:nil]; 
} 

- (void)sliderTouchUp:(UISlider *)sender 
{ 
    [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFY_SLIDER_TOUCH_ENDED object:nil]; 
} 

अब, हम UITableView दोनों में इन अधिसूचनाओं को पकड़ते हैं (ध्यान दें कि तालिकादृश्य वीसी में है लेकिन मुझे यकीन है कि यह काम करेगा यदि आप subcl assed):

- (void)viewDidLoad 
{ 
    // other stuff 
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sliderTouchDown:) name:NOTIFY_SLIDER_TOUCH_BEGAN object:nil]; 
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sliderTouchUp:) name:NOTIFY_SLIDER_TOUCH_ENDED object:nil]; 
} 

- (void)sliderTouchDown:(NSNotification *)notify 
{ 
    self.treatmentTableView.scrollEnabled = NO; 
} 

- (void)sliderTouchUp:(NSNotification *)notify 
{ 
    self.treatmentTableView.scrollEnabled = YES; 
} 

और UIScrollView (समान रूप से ऊपर, एक कुलपति में संलग्न):

- (void)viewDidLoad 
{ 
    // other stuff 

    // Register for slider notifications 
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(disableScrolling:) name:NOTIFY_SLIDER_TOUCH_BEGAN object:nil]; 
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(enableScrolling:) name:NOTIFY_SLIDER_TOUCH_ENDED object:nil]; 
} 

- (void)disableScrolling:(NSNotification *)notify 
{ 
    self.scrollView.scrollEnabled = NO; 
} 

- (void)enableScrolling:(NSNotification *)notify 
{ 
    self.scrollView.scrollEnabled = YES; 
} 

मैं एक और अधिक सुरुचिपूर्ण समाधान जानकर अच्छा लगेगा, लेकिन यह एक निश्चित रूप से काम किया जाता है । जब आप एक स्लाइडर का उपयोग करते हैं, तो तालिका और स्क्रॉलव्यू अभी भी पकड़ते हैं और जब आप स्लाइडर के बाहर क्लिक करते हैं, तो टेबलव्यू और स्क्रॉलव्यू अपेक्षित के रूप में स्थानांतरित होते हैं। साथ ही - ध्यान दें कि मैं इस समाधान में सभी 3 घटकों के गैर-उप-वर्गीकृत उदाहरणों का उपयोग कर सकता हूं। उम्मीद है कि यह किसी की मदद करता है!

1

मैं इसे एक टिप्पणी के रूप में पोस्ट करना चाहता था, लेकिन मेरे खाते में कोई प्रतिनिधि नहीं है इसलिए मुझे पूरा जवाब पोस्ट करना पड़ा। उपयोगकर्ता 762391 का उत्तर हिटटेस्ट ओवरराइड समेत पूरी तरह से काम करता है। मैं सिर्फ इतना है कि जोड़ने के लिए बजाय hitTest अधिभावी की चाहते हैं, आप के बजाय pointInside रद्द कर सकते थे: withEvent: इस तरह (रखने thumbRect विधि):

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent * _Nullable)event { 
    return CGRectContainsPoint([self thumbRect], point) 
} 

या स्विफ्ट में:

var thumbRect: CGRect { 
    return thumbRectForBounds(bounds, trackRect: trackRectForBounds(bounds), value: value) 
} 

override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool { 
    return thumbRect.contains(point) 
} 
1

सबसे upvoted टिप्पणी कोड स्विफ्ट 3 में :)

import Foundation 

class UISliderForScrollView:UISlider { 
    var thumbRect:CGRect { 
     let trackRect = self.trackRect(forBounds: bounds) 
     return thumbRect(forBounds: bounds, trackRect: trackRect, value: value) 
    } 

    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { 
     if thumbRect.contains(point) { 
      return super.hitTest(point, with: event) 
     } else { 
      return superview?.hitTest(point, with: event) 
     } 
    } 
}