UICollectionView horizontal scrolling, deleting last item, animation not working

前端 未结 6 422
我在风中等你
我在风中等你 2021-02-02 00:53

I have a UICollectionView. It scrolls horizontally, has only a single row of items, and behaves like a paging UIScrollView. I\'m making something along the lines of the Safari t

6条回答
  •  醉话见心
    2021-02-02 01:23

    I managed to get my implementation working using the standard UICollectionViewFlowLayout. I had to create the animations manually.

    First, I caused the deleted cell to fade out using a basic animation:

    - (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];
                         }];
    }
    

    Next, I caused the collection view to scroll to the previous cell. Once I've scrolled to the desired cell, I remove the deleted cell.

    - (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];
    }
    

    The only part that is slightly questionable is the dispatch_after(). Unfortunately, -scrollToItemAtIndexPath:atScrollPosition:animated: does not have a completion block, so I had to simulate it. To avoid timing problems, I disabled user interaction. This prevents the user from interacting with the collection view before the cell is removed.

    Another thing I had to watch for is I have to reset my cell's alpha back to 1 due to cell reuse.

    I hope this helps you with your Safari-style tab picker. I know your implementation is different from mine, and I hope that my solution works for you too.

提交回复
热议问题