IndexPath पर UICollectionView ऑटो सेल पर स्क्रॉल करें


101

संग्रह दृश्य लोड करने से पहले उपयोगकर्ता संग्रह दृश्य की सरणी में छवि की संख्या निर्धारित करता है। सभी सेल स्क्रीन पर फिट नहीं होते हैं। मेरे पास 30 सेल हैं और स्क्रीन पर केवल 6 हैं।

प्रश्न: UICollectionView के भार पर वांछित छवि के साथ सेल पर स्क्रॉल कैसे करें?

जवाबों:


90

मैंने पाया है कि स्क्रॉलिंग viewWillAppearमज़बूती से काम नहीं कर सकती क्योंकि संग्रह दृश्य समाप्त नहीं हुआ है यह अभी तक लेआउट नहीं है; आप गलत आइटम पर स्क्रॉल कर सकते हैं।

मैंने यह भी पाया है कि स्क्रॉल viewDidAppearकरने से अनियंत्रित दृश्य के एक क्षणिक फ़्लैश का कारण दिखाई देगा।

और, यदि आप हर बार स्क्रॉल करते हैं viewDidLayoutSubviews, तो उपयोगकर्ता मैन्युअल रूप से स्क्रॉल करने में सक्षम नहीं होगा क्योंकि कुछ संग्रह लेआउट आपके द्वारा स्क्रॉल किए जाने पर सबव्यू लेआउट का कारण बनते हैं।

यहाँ मैंने पाया कि मज़बूती से काम करता है:

उद्देश्य सी :

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

    // If we haven't done the initial scroll, do it once.
    if (!self.initialScrollDone) {
        self.initialScrollDone = YES;

        [self.collectionView scrollToItemAtIndexPath:self.myInitialIndexPath
                                    atScrollPosition:UICollectionViewScrollPositionRight animated:NO];
    }
}

स्विफ्ट:

 override func viewWillLayoutSubviews() {

    super.viewWillLayoutSubviews()

      if (!self.initialScrollDone) {

         self.initialScrollDone = true
         self.testNameCollectionView.scrollToItem(at:selectedIndexPath, at: .centeredHorizontally, animated: true)
    }

}

अच्छी टिप। मैं एक initialScrollDoneध्वज का उपयोग करने पर जोर दूंगा जैसा कि लेनक ने किया है क्योंकि यह विधि एक से अधिक बार कॉल की जाएगी और अगर आप स्क्रॉलटॉइटमएटइंडेक्सपैथ कहते हैं: एक बार से अधिक यह संग्रह दृश्य रेंडर करने के लिए लगता है (आईओएस सिम्युलेटर आईफोन 5 (आईओएस 8)
माज़

1
IOS8 में बढ़िया काम करता है। स्वीकृत उत्तर होना चाहिए।
निक

5
IOS 8.3 में यह मेरे लिए काम नहीं किया। [self.collectionView layoutIfNeeded];पहले फोन करना पड़ता था , जो तब भी काम करता है जब आप ऐसा करते हैं viewDidLoad
ब्रेंट डिलिंगम

1
यह निश्चित रूप से स्वीकृत उत्तर होना चाहिए। ऊपर दिए गए उत्तर ने मुझे एक फ्लैश दिया जैसा कि पहले सेल दिखाया गया था और फिर मेरी नई सेल के साथ अपडेट किया गया, यह विधि मूल रूप से संक्रमण करती है।
सिमोन_सिमली

यह iOS 9 पर भी काम करता है, और मेरे ऑटो लेआउट को भी गड़बड़ नहीं करता है।
मिस्टर ज़ीस्टम

168

नया, संपादित उत्तर:

इसमें जोड़ें viewDidLayoutSubviews

स्विफ्ट

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    let indexPath = IndexPath(item: 12, section: 0)
    self.collectionView.scrollToItem(at: indexPath, at: [.centeredVertically, .centeredHorizontally], animated: true)
}

सामान्य रूप से, .centerVerticallyमामला है

ObjC

-(void)viewDidLayoutSubviews {
   [super viewDidLayoutSubviews];
    NSIndexPath *indexPath = [NSIndexPath indexPathForItem:12 inSection:0];
   [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically | UICollectionViewScrollPositionCenteredHorizontally animated:NO];
}

पुराने उत्तर पुराने iOS के लिए काम कर रहे हैं

इसे इसमें जोड़ें viewWillAppear:

[self.view layoutIfNeeded];
[self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:NO];

4
ठीक यही मैं उपयोग करने की कोशिश कर रहा हूं। मेरे पास सरणी में ऑब्जेक्ट की संख्या है और मुझे उस ऑब्जेक्ट का नाम पता है। लेकिन पता नहीं कैसे सही indexPath डाल ... किसी भी विचार?
अलेक्जेंडर

4
आप आसानी से बना सकते हैं indexPath:[NSIndexPath indexPathForItem:numberOfTheObject inSection:sectionNumber]
boweidmann

3
कुछ त्रुटियां थीं। लेकिन तब मैंने सभी उल्लिखित कोड को अंदर रखा है (शून्य) देखेंDidLayoutSubviews {} और अब यह ठीक काम कर रहा है। थैंक्स बोगदान।
अलेक्जेंडर

1
मैं सेल में 'ज़ूम' कैसे कर सकता हूं, और इसे आवर्धित कर सकता हूं?
फतुहोकू

9
यह iOS 7.1 पर मज़बूती से काम नहीं करता है और संग्रह दृश्य को काली स्क्रीन के रूप में प्रदर्शित कर सकता है। मैं नीचे दिए गए दृश्य में समाधान की तरह स्थिति को बनाए रखना नहीं चाहता था। मैंने जो किया है उसे स्क्रॉल करने के लिए कॉल करने से ठीक पहले एक [self.view LayoutIfNeeded] किया गया है
Daniel Galasko

15

मैं उपरोक्त उत्तर से पूरी तरह सहमत हूं। केवल एक चीज यह है कि मेरे लिए समाधान viewDidAppear में कोड सेट किया गया था

viewDidAppear 
{
    [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:YES];
}

जब मैंने viewWillAppear का उपयोग किया तो स्क्रॉलिंग काम नहीं कर रही थी।


2
viewDidAppear का नुकसान यह है कि आप संग्रह दृश्य को चलते / चमकते हुए देखते हैं, दृश्य पहले ही प्रकट हो चुका है (जैसा कि नाम से पता चलता है) ... मुझे वास्तव में आश्चर्य है कि Apple ने इस तरह के असामान्य मामले को एक अच्छे तरीके से क्यों नहीं डिज़ाइन किया है, viewDidayayoutSubviews का तरीका थोडा अजीब
TheEye

12

यह मेरे लिए काम करने के लिए लग रहा था, यह एक और जवाब के समान है, लेकिन कुछ अलग मतभेद हैं:

- (void)viewDidLayoutSubviews
{     
   [self.collectionView layoutIfNeeded];
   NSArray *visibleItems = [self.collectionView indexPathsForVisibleItems];
   NSIndexPath *currentItem = [visibleItems objectAtIndex:0];
   NSIndexPath *nextItem = [NSIndexPath indexPathForItem:someInt inSection:currentItem.section];

   [self.collectionView scrollToItemAtIndexPath:nextItem atScrollPosition:UICollectionViewScrollPositionNone animated:YES];
}

12

स्विफ्ट:

your_CollectionView.scrollToItemAtIndexPath(indexPath, atScrollPosition: UICollectionViewScrollPosition.CenteredHorizontally, animated: true)

स्विफ्ट 3

let indexPath = IndexPath(row: itemIndex, section: sectionIndex)

collectionView.scrollToItem(at: indexPath, at: UICollectionViewScrollPosition.right, animated: true)

स्क्रॉल स्थिति:

UICollectionViewScrollPosition.CenteredHorizontally / UICollectionViewScrollPosition.CenteredVertically

9

आप इस व्यवहार को प्राप्त करने के लिए ViewDidLoad में मुख्य रन लूप की अगली पुनरावृत्ति में स्क्रॉल भेजने के लिए GCD का उपयोग कर सकते हैं। स्क्रीन पर संग्रह दृश्य दिखाए जाने से पहले स्क्रॉल किया जाएगा, इसलिए कोई चमकती नहीं होगी।

- (void)viewDidLoad {
    dispatch_async (dispatch_get_main_queue (), ^{
        NSIndexPath *indexPath = YOUR_DESIRED_INDEXPATH;
        [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];
    });
}

जब स्थिति 3 है तो इंडेक्सपथ कैसे प्राप्त करें?
केमदो

5

मैं इसे करने की सलाह दूंगा collectionView: willDisplay:तब आप यह सुनिश्चित कर सकते हैं कि संग्रह दृश्य प्रतिनिधि कुछ बचाता है। यहाँ मेरा उदाहरण है:

func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
    /// this is done to set the index on start to 1 to have at index 0 the last image to have a infinity loop
    if !didScrollToSecondIndex {
        self.scrollToItem(at: IndexPath(row: 1, section: 0), at: .left, animated: false)
        didScrollToSecondIndex = true
    }
}

1
मैंने पाया कि विडिसप्ले के बजाय डेडइंडप्लेपिंग का उपयोग करना, इसे ठीक से काम करने का तरीका था। जब तक सेल स्क्रीन पर थी तब तक विलडिसप्ले ठीक था; हालाँकि, यदि सेल अभी तक स्क्रीन पर नहीं थी, तो इस पद्धति ने मुझे इसे स्क्रॉल नहीं किया। didEndDisplaying हालांकि उस उपयोग के मामले के लिए पूरी तरह से काम किया। अपने जवाब की सराहना करते हुए मुझे सही रास्ते पर लाना!
C6Silver

2

उपर्युक्त विकल्प के रूप में। डेटा लोड के बाद कॉल करें:

तीव्र

collectionView.reloadData()
collectionView.layoutIfNeeded()
collectionView.selectItem(at: indexPath, animated: true, scrollPosition: .right)

1

यहां सभी जवाब - हैक। मुझे relaodData के बाद कहीं और संग्रह दृश्य स्क्रॉल करने का बेहतर तरीका मिला है:
उपवर्ग संग्रह दृश्य लेआउट जो आप कभी भी लेआउट का उपयोग करते हैं, विधि तैयारी को ओवरराइड करें, सुपर कॉल सेट के बाद जो आपको कभी भी ऑफ़सेट चाहिए।
ex: https://stackoverflow.com/a/34192787/1400119

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