-->

UICollectionView finishInteractiveTransition witho

2019-06-08 03:00发布

问题:

I'm implementing a custom interactive collection view layout transition, and would like to configure it so that on calling finishInteractiveTransition with a transition layout transitionProgress of 1.0, the completion block of startInteractiveTransitionToCollectionViewLayout:completion: is fired immediately.

I require this behaviour as I would like to be able to immediately start another transition after this one has finished. With this completion block not firing immediately, I end up with nested push animation can result in corrupted navigation bar in the log, since the transition context hasn't had its completeTransition: method called yet.

As it is, even when there is no animation required, there is a small delay of about 0.05s. Is it possible to force UICollectionView to not animate this completion?


Some code...

I have a transition controller that handles both animated & interactive transitions for a navigation transition. The relevant parts of that controller are as follows:

- (void)startInteractiveTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
    self.context = transitionContext;
    UIView *inView = [self.context containerView];
    UICollectionViewController *fromCVC = (UICollectionViewController *)[self.context viewControllerForKey:UITransitionContextFromViewControllerKey];
    UICollectionViewController *toCVC = (UICollectionViewController *)[self.context viewControllerForKey:UITransitionContextToViewControllerKey];

    self.transitionLayout = (MyTransitionLayout *)[fromCVC.collectionView startInteractiveTransitionToCollectionViewLayout:toCVC.collectionViewLayout completion:^(BOOL completed, BOOL finish) {
        [self.context completeTransition:completed];
        [inView addSubview:toCVC.view];
    }];
}

- (void)updateInteractiveTransition:(CGFloat)progress
{
    if (!self.context) return;
    self.percentComplete = progress;
    if (self.percentComplete != self.transitionLayout.transitionProgress) {
        self.transitionLayout.transitionProgress = self.percentComplete;
        [self.transitionLayout invalidateLayout];
        [self.context updateInteractiveTransition:self.percentComplete];
    }
}

- (void)finishInteractiveTransition
{
    if (!self.context) return;
    UICollectionViewController *fromCVC = (UICollectionViewController *)[self.context viewControllerForKey:UITransitionContextFromViewControllerKey];
    [fromCVC.collectionView finishInteractiveTransition];
    [self.context finishInteractiveTransition];
}

- (void)cancelInteractiveTransition
{
    if (!self.context) return;
    UICollectionViewController *fromCVC = (UICollectionViewController *)[self.context viewControllerForKey:UITransitionContextFromViewControllerKey];
    [fromCVC.collectionView cancelInteractiveTransition];
    [self.context cancelInteractiveTransition];
}

I've verified that on calling finishInteractiveTransition the transition layout's transitionProgress is exactly 1.0. According to the UIViewControllerTransitioning.h header file, the completionSpeed defaults to 1.0, resulting in a completion duration of (1 - percentComplete)*duration, so the duration should be 0, but it's not... it's taking at least a couple of run loops before the completion block is called.

Is it possible to do what I want, or will I have to implement my own version of startInteractiveTransitionToCollectionViewLayout:completion:? (not the end of the world, but I'd rather stick to the standard APIs where possible...)