2012-10-26 6 views
11

मेरे पास एक UICollectionView है। यह क्षैतिज स्क्रॉल करता है, केवल वस्तुओं की एक पंक्ति है, और एक पेजिंग UIScrollView की तरह व्यवहार करता है। मैं सफारी टैब पिकर की तर्ज पर कुछ कर रहा हूं, ताकि आप अभी भी प्रत्येक आइटम के किनारे को देख सकें। मेरे पास केवल एक खंड है।UICollectionViz क्षैतिज स्क्रॉलिंग, अंतिम आइटम को हटाने, एनीमेशन काम नहीं कर रहा

यदि मैं कोई आइटम हटाता हूं जो अंतिम आइटम नहीं है, तो सब कुछ अपेक्षित काम करता है और दाईं ओर एक नई वस्तु स्लाइड होती है।

यदि मैं अंतिम आइटम हटा देता हूं, तो संग्रह दृश्य की स्क्रॉल स्थिति N-1th आइटम पर कूद जाती है (आसानी से एनिमेट नहीं होती है), और फिर मुझे एनएच आइटम (जिसे मैंने हटाया है) फीका दिखाई देता है।

यह व्यवहार मेरे द्वारा किए गए कस्टम लेआउट से संबंधित नहीं है, क्योंकि यह तब भी होता है जब मैं इसे सादा प्रवाह लेआउट का उपयोग करने के लिए स्विच करता हूं।

[self.tabCollectionView deleteItemsAtIndexPaths:@[[NSIndexPath indexPathForItem:index inSection:0]]]; 

किसी और को यह अनुभव किया है: मैं का उपयोग कर आइटम को हटा रहा हूं? क्या यह UICollectionView में एक बग है, और क्या कोई कामकाज है?

+0

मैं भी एक सफारी शैली टैब UICollectionView का उपयोग कर पिकर को लागू किया गया है। मैं वही अजीब एनिमेशन देख रहा हूं, और मुझे अभी तक कोई काम नहीं मिला है। – rbrown

+0

आपको '-ShouldInvalidateLayoutForBoundsChange:' लागू करने का प्रयास करना चाहिए और जब आप अंतिम आइटम को हटा रहे हैं तो वापस न करें। इसने मेरे सफारी-स्टाइल टैब के साथ सभी समस्याओं को ठीक नहीं किया है, लेकिन इससे कुछ एनिमेशन में मदद मिली है। – rbrown

उत्तर

4

मैं मानक UICollectionViewFlowLayout का उपयोग करके अपना कार्यान्वयन कार्य करने में कामयाब रहा। मुझे मैन्युअल रूप से एनिमेशन बनाना था।

पहले, मैं हटाए गए कक्ष एक बुनियादी एनीमेशन का उपयोग कर बाहर फीका करने के लिए कारण:

- (void)tappedCloseButtonOnCell:(ScreenCell *)cell { 

    // We don't want to close our last screen. 
    if ([self screenCount] == 1u) { 
     return; 
    } 

    [UIView animateWithDuration:UINavigationControllerHideShowBarDuration 
        animations:^{ 
         // Fade out the cell. 
         cell.alpha = 0.0f; 
        } 
        completion:^(BOOL finished) { 

         NSIndexPath *indexPath = [self.collectionView indexPathForCell:cell]; 
         UIViewController *screen = [self viewControllerAtIndex:indexPath.item]; 

         [self removeScreen:screen animated:YES]; 
        }]; 
} 

इसके बाद, मैं संग्रह दृश्य पिछले सेल पर स्क्रॉल करने के लिए कारण होता है। एक बार जब मैं वांछित सेल पर स्क्रॉल कर लेता हूं, तो मैं हटाए गए सेल को हटा देता हूं।

- (void)removeScreen:(UIViewController *)screen animated:(BOOL)animated { 

    NSParameterAssert(screen); 

    NSInteger index = [[self.viewControllerDictionaries valueForKeyPath:kViewControllerKey] indexOfObject:screen]; 

    if (index == NSNotFound) { 
     return; 
    } 

    [screen willMoveToParentViewController:nil]; 

    if (animated) { 

     dispatch_time_t popTime = DISPATCH_TIME_NOW; 
     NSIndexPath *indexPath = [NSIndexPath indexPathForItem:index 
               inSection:0]; 

     // Disables user interaction to make sure the user can't interact with 
     // the collection view during the time between when the scroll animation 
     // ends and the deleted cell is removed. 
     [self.collectionView setUserInteractionEnabled:NO]; 

     // Scrolls to the previous item, if one exists. If we are at the first 
     // item, we just let the next screen slide in from the right. 
     if (index > 0) { 
      popTime = dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC); 
      NSIndexPath *targetIndexPath = [NSIndexPath indexPathForItem:index - 1 
                inSection:0]; 
      [self.collectionView scrollToItemAtIndexPath:targetIndexPath 
             atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally 
               animated:YES]; 
     } 

     // Uses dispatch_after since -scrollToItemAtIndexPath:atScrollPosition:animated: 
     // doesn't have a completion block. 
     dispatch_after(popTime, dispatch_get_main_queue(), ^{ 

      [self.collectionView performBatchUpdates:^{ 
       [self.viewControllerDictionaries removeObjectAtIndex:index]; 
       [self.collectionView deleteItemsAtIndexPaths:@[indexPath]]; 
       [screen removeFromParentViewController]; 
       [self.collectionView setUserInteractionEnabled:YES]; 
      } completion:NULL]; 
     }); 

    } else { 
     [self.viewControllerDictionaries removeObjectAtIndex:index]; 
     [self.collectionView reloadData]; 
     [screen removeFromParentViewController]; 
    } 

    self.addPageButton.enabled = YES; 
    [self postScreenChangeNotification]; 
} 

एकमात्र हिस्सा जो थोड़ा संदिग्ध है dispatch_after() है। दुर्भाग्यवश, -scrollToItemAtIndexPath:atScrollPosition:animated: में पूरा होने वाला ब्लॉक नहीं है, इसलिए मुझे इसे अनुकरण करना था। समय की समस्याओं से बचने के लिए, मैंने उपयोगकर्ता इंटरैक्शन को अक्षम कर दिया। यह उपयोगकर्ता को हटाए जाने से पहले संग्रह दृश्य के साथ बातचीत करने से रोकता है।

एक और चीज़ जो मुझे देखना है, मुझे सेल पुन: उपयोग के कारण अपने सेल के अल्फा को 1 पर रीसेट करना है।

मुझे आशा है कि यह आपको अपने सफारी-स्टाइल टैब पिकर के साथ मदद करेगा। मुझे पता है कि आपका कार्यान्वयन मेरा से अलग है, और मुझे आशा है कि मेरा समाधान भी आपके लिए काम करेगा।

+0

उत्तर के लिए धन्यवाद! मैं जल्द ही इसे आज़माउंगा और आपको बता दूंगा कि यह कैसा चल रहा है। –

1

मैं जानता हूँ कि यह पहले से ही एक जवाब है, लेकिन मैं एक अलग तरह से एक सेट अंतराल के बाद भेजने की आवश्यकता नहीं है कि इस कार्यान्वित किया।

अपने हटाना विधि में आप निर्धारित करने के लिए पिछले आइटम हटाया जा रहा था एक चेक करना होगा। यदि इसे निम्न पर कॉल किया गया था:

if(self.selection == self.assets.count-1 && self.selection != 0){ 
    isDeleting = YES; 
    [collection scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:self.selection-1 inSection:0] atScrollPosition:UICollectionViewScrollPositionLeft animated:YES]; 
} 

मान लीजिए चयन चयनित आइटम है जिसे आप हटा रहे हैं। यह आइटम के बाईं ओर स्क्रॉल करेगा। नोट करें कि अगर कथन जांच रहा है कि यह एकमात्र आइटम नहीं है। यदि यह थे कॉल क्योंकि वहां कोई -1 पंक्ति दुर्घटना होगा।

तो आप निम्न विधि है जो जब स्क्रॉल एनीमेशन पूरा हो गया है कहा जाता है लागू कर सकते हैं। मैं बस deleteObjectInCollection विधि में कोई करने isDeleting सेट और यह सब काम करने के लिए लगता है।

- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView{ 
    if(isDeleting){ 
     [self deleteObjectInCollection]; 
    } 
} 

मुझे उम्मीद है कि इससे मदद मिलती है।

0

और यहाँ अभी तक एक समाधान है (targetIndexPath सेल के indexPath हटा दिया जाना चाहिए है)। इस कोड को बस एक removeCellAtIndexPath में रखा जा सकता है: (NSIndexPath *) targetIndexPath विधि और बस हो गया (सार्वजनिक कोड के लिए अपने कोड से मेरी रूपांतरों संभालने सही हैं, अन्यथा मुझसे पूछते हैं और मैं मदद करने की कोशिश करेंगे)।

// (Here it's assumed that self.collectionView.collectionViewLayout has been assigned a UICollectionViewFlowLayout before; note the word "FLOW" in that class name) 
UICollectionViewFlowLayout* layout = (UICollectionViewFlowLayout*) self.collectionView.collectionViewLayout; 

// Find index path of the last cell in collection view: 
NSIndexPath* lastIndexPath = [self lastItemIndexPath]; 

// Extend content area temporarily to fill out space left by the last row after deletion, if last row is visible: 
BOOL lastRowWasVisible = NO; 
if ([self.collectionView icn_cellAtIndexPathIsVisible:lastIndexPath]) { 

    lastRowWasVisible = YES; 

    // Adapt section spacing to temporarily fill out the space potentially left after removing last cell: 
    CGFloat cellWithLineSpacingHeight = 79.0f + 8.0f; // Height of my cell + one line spacing 
    layout.sectionInset = UIEdgeInsetsMake(0.0f, 0.0f, cellWithLineSpacingHeight, 0.0f); 
} 

// Remove the cell: 
[self.collectionView performBatchUpdates:^{ 

    [self.collectionView deleteItemsAtIndexPaths:[NSArray arrayWithObject:targetIndexPath]]; 

} completion:^(BOOL finished) { 

    // Only scroll if we had the last row visible: 
    if (lastRowWasVisible) { 

     NSIndexPath* lastItemIndexPath = [self lastItemIndexPath]; 

     // Run a custom scroll animation for two reasons; 1. that way we can reset the insets when animation is finished, and 2. using the "animated:YES" option lags here for some reason: 
     [UIView animateWithDuration:0.3f animations:^{ 
      [self.collectionView scrollToItemAtIndexPath:prevItemIndexPath atScrollPosition:UICollectionViewScrollPositionBottom animated:NO]; 
     } completion:^(BOOL finished) { 

      // Reset the space placeholder once having scrolled away from it: 
      layout.sectionInset = UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 0.0f); 
     }]; 
    } 
}]; 

icn_cellAtIndexPathIsVisible: विधि UICollectionView पर सिर्फ एक वर्ग है:

- (BOOL) icn_cellAtIndexPathIsVisible:(NSIndexPath*)indexPath { 

    BOOL __block wasVisible = NO; 
    [self.indexPathsForVisibleItems enumerateObjectsUsingBlock:^(NSIndexPath* ip, NSUInteger idx, BOOL *stop) { 

     if ([ip isEqual:indexPath]) { 

      wasVisible = YES; 
      *stop = YES; 
     } 
    }]; 

    return wasVisible; 
} 

अद्यतन: यह केवल एक अनुभाग के साथ काम करता है।

0

एक सस्ता समाधान अंतिम सेल के रूप में एक और 0px सेल को जोड़ने के लिए और इसे हटाने के लिए कभी नहीं है।

func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) { 
    if indexPath.row < collectibles.count - 1 { // dont delete the last one. just because the animation isn't working 
     collectibles.removeAtIndex(indexPath.row) 
     collectionView.deleteItemsAtIndexPaths([indexPath]) 
    } 
} 
0

मुझे छवि संग्रह संग्रह के माध्यम से एक पंक्ति क्षैतिज स्क्रॉलिंग के साथ एक समान समस्या का सामना करना पड़ रहा था। जब मैं संग्रह दृश्य के contentSize को सेट करने के लिए अपना कोड हटा देता हूं तो यह समस्या गायब हो जाती है, ऐसा लगता है कि यह स्वचालित रूप से इसे संभालने लगता है।

नहीं एक विशेष रूप से वर्बोज़ जवाब है, लेकिन मैं यह मदद करता है उम्मीद है।

0

यह काम करेगा:

collectionView.collectionViewLayout.invalidateLayout() 

collectionView.layoutIfNeeded() 
संबंधित मुद्दे