使用一种动画同时关闭和呈现模态视图控制器

8
问题在于我不知道如何使用一个转换动画来解除和呈现视图控制器。
我的故事板结构是:
我们可以说A控制器是跟随NavigationController的,B是启动引用,C是TabBar ViewController。 BC都以交叉溶解的方式被模态呈现。
当用户登录应用程序(从B)时,C控制器以水平翻转的方式被模态呈现。当用户注销(从C)时,B以同样的方式呈现。 在A控制器上,我根据用户是否已登录直接进行segue到BC
我的问题是,如果我不从BC中解除上一个视图控制器,那么该控制器会泄漏。相反,如果我解除它,A将在目标控制器(BC)呈现之前显示。
是否可能仅显示A视图并跳过水平翻转转换?
3个回答

5

我解决这个问题的方法是替换当前的rootViewController,并支持不同的转场效果:

static func replaceRootViewController(with viewController: UIViewController, transition: UIViewAnimationOptions, completion: (() -> ())? = nil) {        
    if transition == .transitionCrossDissolve {
        let overlayView = UIScreen.main.snapshotView(afterScreenUpdates: false)
        viewController.view.addSubview(overlayView)
        UIApplication.shared.keyWindow?.rootViewController = viewController

        UIView.animate(withDuration: 0.65, delay: 0, options: transition, animations: {
            overlayView.alpha = 0
        }, completion: { finished in
            overlayView.removeFromSuperview()
            if let completion = completion{
                completion()
            }
        })
    } else {
        _ = viewController.view
        UIView.transition(with: UIApplication.shared.keyWindow!, duration: 0.65,options: transition, animations: {
            UIApplication.shared.keyWindow?.rootViewController = viewController
        }){_ in
            if let completion = completion {
                completion()
            }

        }
    }
}

2

两个答案都非常有帮助,这是 Swift 4 版本:

func presentHidingBehindScreenSnapshot(viewController: UIViewController,
                                     completion: (() -> (Void))? ) {
if let screenSnapshot = UIApplication.shared.keyWindow?.snapshotView(afterScreenUpdates: false),
  let rootViewController = UIApplication.shared.keyWindow?.rootViewController {
  rootViewController.view.addSubview(screenSnapshot)
  rootViewController.view.bringSubview(toFront: screenSnapshot)

  rootViewController.dismiss(animated: false, completion: {
    rootViewController.present(viewController, animated: false, completion: {
      screenSnapshot.removeFromSuperview()
      if let existingCompletion = completion {
        existingCompletion()
      }
    })
  })
} else {
  #if DEBUG
  fatalError("Can't hide behind snapshot while presenting other view controller")
  #endif
}

}


2
这是我用于解决这个问题的一个解决方案。由于我不使用Storyboard,所以不知道它如何与之集成。
在UIViewController的类别中添加此方法,然后可以在任何地方调用先前调用的"presentViewController:animated:completion"方法。结果是在仍然关闭前一个控制器的情况下,新控制器的动画无缝进行。
-(void)presentViewControllerDismissingPrevious:(UIViewController* _Nonnull)controller animated:(BOOL)animated completion:(void (^ __nullable)(void))completion {

    UIViewController* visibleController = self;
    {
        UIViewController* temp;
        while( ( temp = visibleController.presentedViewController ) != nil ) {
            visibleController = temp;
        }
    }

    if( visibleController == self ) {
        // no previous controller to dismiss
        [self presentViewController:controller animated:animated completion:completion];
    } else {
        // create a temporary snapshot of the visible controller's entire window
        // and add to the current view controller's window until animation completed
        UIWindow* visibleWindow = visibleController.view.window;
        UIView* tempView = [visibleWindow snapshotViewAfterScreenUpdates:NO];
        UIView* rootView = self.view.window.subviews[0];
        tempView.frame = [rootView convertRect:visibleWindow.bounds fromView:visibleWindow];
        [rootView addSubview:tempView];

        [self dismissViewControllerAnimated:NO completion:^(){
            [self presentViewController:controller animated:animated completion:^(){
                [tempView removeFromSuperview];
                if( completion ) {
                    completion();
                }
            }];
        }];
    }
}

抱歉回复晚了,发帖几天后我找到了解决方法,但是忘记在这里发布了。 我的做法与你的解决方案非常相似,但更加完整(还支持翻转动画)。 - kikettas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接