2009-08-03 13 views
86

मोबाइल सफारी आपको नीचे दिए गए पृष्ठ नियंत्रण के साथ एक प्रकार के UIScrollView क्षैतिज पेजिंग दृश्य दर्ज करके पृष्ठों को स्विच करने की अनुमति देता है।UIScrollView क्षैतिज पेजिंग जैसे मोबाइल सफारी टैब

मैं इस विशेष व्यवहार को दोहराने की कोशिश कर रहा हूं जहां क्षैतिज स्क्रॉल करने योग्य UIScrollView अगले दृश्य की कुछ सामग्री दिखाता है।

ऐप्पल ने उदाहरण प्रदान किया: पेजकंट्रोल दिखाता है कि क्षैतिज पेजिंग के लिए UIScrollView का उपयोग कैसे करें, लेकिन सभी विचार पूरे स्क्रीन चौड़ाई को लेते हैं।

मोबाइल सफारी जैसे अगले दृश्य की कुछ सामग्री दिखाने के लिए मैं UIScrollView कैसे प्राप्त करूं?

+2

बस एक विचार ...स्क्रॉल व्यू की स्क्रीन को स्क्रीन से छोटा बनाने की कोशिश करें, और दृश्यों को ठीक से प्रदर्शित करने के साथ चारों ओर झुकाएं। (और स्क्रॉल व्यू के क्लिप को सेट करने के लिए सेट करें) – mjhoy

+0

मैं पेजों को uiscrollview की चौड़ाई (क्षैतिज स्क्रॉल) को बड़ा करना चाहता था। और mjhoy के विचार वास्तव में मेरी मदद की! – Sasho

+0

संबंधित है [सामग्री आकार से छोटे वेतन वृद्धि में PISIS UIScrollView] (http://stackoverflow.com/q/1677085/590956)। – Sam

उत्तर

258

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

फिर, चूंकि आप अन्य पृष्ठों को देखना चाहते हैं, निश्चित रूप से, clipsToBounds से NO पर सेट करें क्योंकि mhjoy ने कहा। जब चाल उपयोगकर्ता UIScrollView के फ्रेम के बाहर ड्रैग शुरू करता है तो चाल भाग अब स्क्रॉल करने जा रहा है। मेरे समाधान इस प्रकार है (जब मैं इस बहुत हाल ही में करना था) था के रूप में:

एक UIView उपवर्ग (अर्थात ClipView) कि UIScrollView शामिल होंगे बनाएँ और यह subviews है। अनिवार्य रूप से, आपके पास सामान्य परिस्थितियों में क्या होगा, इसका फ्रेम होना चाहिए। ClipView के केंद्र में UIScrollView रखें। सुनिश्चित करें कि ClipView का clipsToBoundsYES पर सेट किया गया है यदि इसकी चौड़ाई इसके मूल दृश्य से कम है। इसके अलावा, ClipView को UIScrollView के संदर्भ की आवश्यकता है।

अंतिम चरण - (UIView *)hitTest:withEvent:ClipView के अंदर ओवरराइड करना है।

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { 
    return [self pointInside:point withEvent:event] ? scrollView : nil; 
} 

यह मूलतः अपने माता-पिता के देखने के फ्रेम करने के लिए UIScrollView के स्पर्श क्षेत्र का विस्तार, आप वास्तव में क्या जरूरत है।

एक अन्य विकल्प हालांकि आप अभी भी एक कंटेनर को देखने की जरूरत है कतरन करने के लिए होगा UIScrollView उपवर्ग और उसके - (BOOL)pointInside:(CGPoint) point withEvent:(UIEvent *) event विधि ओवरराइड करने के लिए हो सकता है, है, और यह केवल UIScrollView के फ्रेम पर YES आधारित लौटने के लिए निर्धारित करने के लिए मुश्किल हो सकता है।

नोट:अगर आप subview उपयोगकर्ता बातचीत को लेकर कुछ समस्याएँ तुम भी जूरी Pakaste के hitTest:withEvent: modification पर एक नज़र रखना चाहिए।

+3

धन्यवाद एड। मैं विचारों के आलसी लोडिंग ('लेआउटस्यूब्यूव्यू 'में) के लिए' UIScrollView' उपclass के साथ गया था, और' pointInside: withEvent: 'परीक्षण करने के लिए 'क्लिपिंगरक्ट' का उपयोग किया। वास्तव में अच्छी तरह से काम करता है, और कोई अतिरिक्त कंटेनर दृश्य की आवश्यकता है। – ohhorob

+1

ग्रेट उत्तर। मैंने @ यूहोरोलव्यू 'उपclass का उपयोग @ohhorob जैसा किया था, लेकिन क्लिपिंग के लिए एक कंटेनर व्यू के साथ और [सुपर पॉइंट इनसाइड: CGPointMake (self.contentOffset.x + self.frame.size.width/2, self.contentOffset.y + self। frame.size.height/2) withEvent: event]; '' बिंदु 'के अंदर: के साथ:'। यह बहुत अच्छी तरह से काम करता है और @ जुरीपाकस्ट के उत्तर में उल्लिखित उपयोगकर्ता इंटरैक्शन के साथ कोई समस्या नहीं है। – cduck

+0

वाह, यह वास्तव में एक अच्छा समाधान है। हालांकि, बस एक चीज, मेरे सेटअप पर, जिन पृष्ठों को मैं जोड़ रहा हूं उनमें UIButtons हैं। जब मैं हिटटेस्ट विधि को ओवरराइड करता हूं तो यह मुझे उन बटनों पर टैप करने नहीं देता है। मैं स्क्रॉल कर सकता हूं, लेकिन किसी भी पेज के अंदर कोई कार्रवाई नहीं की जा सकती है। –

68

ऊपर दिए गए ClipView समाधान मेरे लिए काम किया, लेकिन मुझे एक अलग -[UIView hitTest:withEvent:] कार्यान्वयन करना पड़ा। एड मार्टी के संस्करण को क्षैतिज एक के अंदर लंबवत स्क्रॉलव्यू के साथ काम करने वाले उपयोगकर्ता इंटरैक्शन नहीं मिला।

निम्न संस्करण मेरे लिए काम किया:

-(UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event 
{ 
    UIView* child = nil; 
    if ((child = [super hitTest:point withEvent:event]) == self) 
     return self.scrollView;  
    return child; 
} 
+0

यह उपयोगकर्ता इंटरैक्शन काम करने के साथ बटन और अन्य सबव्यू प्राप्त करने में भी मदद करता है। :) धन्यवाद –

+4

इस कोड के लिए धन्यवाद, मैं स्क्रॉलव्यू सीमाओं में शामिल सबव्यू (बटन) से ईवेंट प्राप्त करने के लिए इस संशोधन का उपयोग कैसे कर सकता हूं? यह काम करता है अगर उदाहरण के लिए एक बटन केंद्रीय स्क्रॉलव्यू की सीमाओं के भीतर है लेकिन बाहर नहीं है। – DreamOfMirrors

+4

यह वास्तव में मदद की। इसे चयनित उत्तर के संशोधन के रूप में शामिल किया जाना चाहिए। – Pacu

3

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

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event 
{ 
    if (([self pointInside:point withEvent:event]) && (self.subviews.count >= 1)) 
    { 
     // An extended-hit view should only have one sub-view, or make sure the 
     // first subview is the one you want to expand the hit test for. 
     return [self.subviews objectAtIndex:0]; 
    } 

    return nil; 
} 
4

मैं एक और कार्यान्वयन जो scrollview स्वचालित रूप से वापस कर सकते हैं बना दिया है। इसलिए इसे आईबीओटलेट रखने की आवश्यकता नहीं है जो परियोजना में पुन: उपयोग को सीमित कर देगी।

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event 
{ 
    if ([self pointInside:point withEvent:event]) { 
     for (id view in [self subviews]) { 
      if ([view isKindOfClass:[UIScrollView class]]) { 
       return view; 
      } 
     } 
    } 
    return nil; 
} 
+1

यदि आपके पास पहले से ही xib/storyboard है तो यह उपयोग करने वाला एक है। अन्यथा मुझे यकीन नहीं है कि आप पेजिंग/स्क्रॉलव्यू का संदर्भ कैसे प्राप्त करेंगे। कोई विचार? – mskw

3

मैं ऊपर upvoted सुझाव लागू होने, लेकिन UICollectionView मैं फ्रेम से बाहर माना कुछ भी उपयोग कर रहा था स्क्रीन बंद किया जाना है। इसने आस-पास की कोशिकाओं को केवल सीमाओं से बाहर करने के लिए प्रेरित किया जब उपयोगकर्ता उनके प्रति स्क्रॉल कर रहा था, जो आदर्श नहीं था।

जो मैंने समाप्त किया वह प्रतिनिधि (या UICollectionViewLayout) के नीचे विधि को जोड़कर स्क्रॉलव्यू के व्यवहार को अनुकरण कर रहा था।

- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity 
{  
    if (velocity.x > 0) { 
    proposedContentOffset.x = ceilf(self.collectionView.contentOffset.x/pageSize) * pageSize; 
    } 
    else { 
    proposedContentOffset.x = floorf(self.collectionView.contentOffset.x/pageSize) * pageSize; 
    } 

    return proposedContentOffset; 
} 

इस कड़ी चोट कार्रवाई के प्रतिनिधिमंडल पूरी तरह से है, जो भी एक बोनस था बचा जाता है। UIScrollViewDelegate में scrollViewWillEndDragging:withVelocity:targetContentOffset: नामक एक ही विधि है जिसका उपयोग UITableViews और UIScrollViews पृष्ठ पर किया जा सकता है।

+2

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

2

मेरी संस्करण बटन स्क्रॉल पर झूठ बोल दबाने - काम =)

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { 
    UIView* child = nil; 
    for (int i=0; i<[[[[self subviews] objectAtIndex:0] subviews] count];i++) { 

     CGRect myframe =[[[[[self subviews] objectAtIndex:0] subviews]objectAtIndex:i] frame]; 
     CGRect myframeS =[[[self subviews] objectAtIndex:0] frame]; 
     CGPoint myscroll =[[[self subviews] objectAtIndex:0] contentOffset]; 
     if (myframe.origin.x < point.x && point.x < myframe.origin.x+myframe.size.width && 
      myframe.origin.y+myframeS.origin.y < point.y+myscroll.y && point.y+myscroll.y < myframe.origin.y+myframeS.origin.y +myframe.size.height){ 
      child = [[[[self subviews] objectAtIndex:0] subviews]objectAtIndex:i]; 
      return child; 
     } 


    } 

    child = [super hitTest:point withEvent:event]; 
    if (child == self) 
     return [[self subviews] objectAtIndex:0]; 
    return child; 
    } 

लेकिन केवल [[आत्म subviews] objectAtIndex: 0] एक स्क्रॉल

+0

यह मेरी समस्या हल करता है :) बस ध्यान दें कि जब आप सीमाओं की जांच कर रहे हैं तो आप scroll.x पर स्क्रॉल ऑफ़सेट नहीं जोड़ रहे हैं, और इससे कोड क्षैतिज स्क्रॉल पर अच्छी तरह से काम नहीं करता है। इसे जोड़ने के बाद, यह ठीक काम किया! – Bartserk

3

बच्चे पर नल घटनाओं फायरिंग सक्षम होना चाहिए इस SO प्रश्न की तकनीक का समर्थन करते समय स्क्रॉल व्यू के विचार। पठनीयता के लिए स्क्रॉल व्यू (self.scrollView) का संदर्भ उपयोग करता है।

- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event 
{ 
    UIView *hitView = nil; 
    NSArray *childViews = [self.scrollView subviews]; 
    for (NSUInteger i = 0; i < childViews.count; i++) { 
     CGRect childFrame = [[childViews objectAtIndex:i] frame]; 
     CGRect scrollFrame = self.scrollView.frame; 
     CGPoint contentOffset = self.scrollView.contentOffset; 
     if (childFrame.origin.x + scrollFrame.origin.x < point.x + contentOffset.x && 
      point.x + contentOffset.x < childFrame.origin.x + scrollFrame.origin.x + childFrame.size.width && 
      childFrame.origin.y + scrollFrame.origin.y < point.y + contentOffset.y && 
      point.y + contentOffset.y < childFrame.origin.y + scrollFrame.origin.y + childFrame.size.height 
     ){ 
      hitView = [childViews objectAtIndex:i]; 
      return hitView; 
     } 
    } 
    hitView = [super hitTest:point withEvent:event]; 
    if (hitView == self) 
     return self.scrollView; 
    return hitView; 
} 

अपने बच्चे को देखने के लिए इस जोड़े स्पर्श घटना पर कब्जा करने की:।।

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

(यह user1856273 के समाधान के एक विविधता है पठनीयता के लिए ऊपर साफ़ किया और शामिल किया Bartserk के बग फिक्स मैं संपादन user1856273 के बारे में सोचा उत्तर दें, लेकिन यह बनाने में बहुत बड़ा बदलाव था।)

+0

सबव्यू में एम्बेडेड UIButton पर काम करने के लिए टैप करने के लिए, मैंने कोड हिटव्यू = [childViews objectAtIndex: i] को बदल दिया; // के साथ UIButton (UIView * paneView [[childViews objectAtIndex: i] सबव्यूज़] में खोजें() { अगर ([paneView isKindOfClass: [UIButton class]]) वापसी फलक व्यू; } – CharlesA

5

मैं कस्टम यूआईएसक्रॉल व्यू के साथ जा रहा था क्योंकि यह मुझे लगता है कि यह सबसे तेज़ और सरल तरीका था। हालांकि, मुझे कोई सटीक कोड नहीं मिला, इसलिए मैंने सोचा कि मैं साझा करूंगा। मेरी ज़रूरतें एक यूआईएसक्रोल व्यू के लिए थीं, जिसमें छोटी सामग्री थी और इसलिए यूआईएसक्रॉल व्यू पेजिंग प्रभाव को प्राप्त करने के लिए छोटा था। पोस्ट स्टेटस के रूप में आप पूरे स्वाइप नहीं कर सकते हैं। लेकिन अब आप कर सकते हैं।

क्लास कस्टमस्क्रॉल व्यू और उपclass UIScrollView बनाएँ। तो फिर तुम सब करने की जरूरत है .m फ़ाइल में इस ऐड जाता है:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { 
    return (point.y >= 0 && point.y <= self.frame.size.height); 
} 

यह आपको पक्ष की ओर से स्क्रॉल करने के लिए (क्षैतिज) की अनुमति देता है। अपने स्वाइप/स्क्रॉलिंग स्पर्श क्षेत्र को सेट करने के लिए तदनुसार सीमा समायोजित करें। का आनंद लें! अपने पृष्ठों आकार के रूप में scrollview की

6

सेट फ्रेम आकार होगा:

[self.view addSubview:scrollView]; 
[self.view addGestureRecognizer:mainScrollView.panGestureRecognizer]; 

अब आप self.view पर पैन कर सकते हैं, और scrollview पर सामग्री स्क्रॉल कर दिया जाएगा।
सामग्री को क्लिप करने से रोकने के लिए scrollView.clipsToBounds = NO; का भी उपयोग करें।

संबंधित मुद्दे