標準の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つ注意しなければならないのは、セルの再利用のためにセルのアルファを1に戻す必要があることです。
これは、Safariスタイルのタブ選択ツールでお役に立てれば幸いです。あなたの実装は私のものとは異なることを知っています。私のソリューションがあなたにも役立つことを願っています。
を私もUICollectionViewを使用してサファリスタイルのタブピッカーを実施してきました。私は同じ不思議なアニメーションを見てきましたが、私はまだ何の回避策も見つけていません。 – rbrown
'-shouldInvalidateLayoutForBoundsChange:'を実装して、最後の項目を削除するときはNOを返してください。これは私のSafariスタイルのタブのすべての問題を修正していませんが、いくつかのアニメーションに役立っています。 – rbrown