跳到主要内容

转场与导航

问题

iOS 的页面跳转方式有哪些?如何自定义转场动画?

答案

页面跳转方式

方式说明适用场景
pushViewController入栈导航详情页、列表→详情
present模态展示登录、图片预览
UITabBarControllerTab 切换底部标签栏
UIPageViewController翻页引导页、图片浏览

自定义 Push 转场

class FadeAnimator: NSObject, UIViewControllerAnimatedTransitioning {
let isPresenting: Bool

init(isPresenting: Bool) {
self.isPresenting = isPresenting
}

func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.3
}

func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let containerView = transitionContext.containerView
guard let toView = transitionContext.view(forKey: .to),
let fromView = transitionContext.view(forKey: .from) else { return }

if isPresenting {
containerView.addSubview(toView)
toView.alpha = 0
UIView.animate(withDuration: transitionDuration(using: transitionContext)) {
toView.alpha = 1
} completion: { finished in
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
}
} else {
UIView.animate(withDuration: transitionDuration(using: transitionContext)) {
fromView.alpha = 0
} completion: { finished in
fromView.removeFromSuperview()
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
}
}
}
}

// 设置代理
class VC: UIViewController, UINavigationControllerDelegate {
func navigationController(_ navigationController: UINavigationController,
animationControllerFor operation: UINavigationController.Operation,
from fromVC: UIViewController, to toVC: UIViewController)
-> UIViewControllerAnimatedTransitioning? {
return FadeAnimator(isPresenting: operation == .push)
}
}

交互式转场

配合手势实现可交互的返回动画:

class InteractiveTransition: UIPercentDrivenInteractiveTransition {
var interacting = false

func handlePan(_ gesture: UIPanGestureRecognizer) {
let translation = gesture.translation(in: gesture.view?.superview)
let progress = min(max(translation.x / UIScreen.main.bounds.width, 0), 1)

switch gesture.state {
case .began:
interacting = true
navigationController?.popViewController(animated: true)
case .changed:
update(progress)
case .ended, .cancelled:
interacting = false
progress > 0.5 ? finish() : cancel()
default: break
}
}
}

常见面试问题

Q1: present 的 modalPresentationStyle 有哪些?

答案

样式iOS说明
.automatic13+默认(通常为 pageSheet)
.fullScreen2+全屏覆盖
.pageSheet3.2+卡片式(iOS 13+ 可下拉关闭)
.overFullScreen8+全屏但不移除底部 VC
.popover8+弹出气泡(iPad 常用)
.custom7+完全自定义

Q2: 自定义转场动画需要实现哪些协议?

答案

  1. UIViewControllerTransitioningDelegate:返回动画控制器和交互控制器
  2. UIViewControllerAnimatedTransitioning:定义动画内容和时长
  3. UIViewControllerInteractiveTransitioning:交互式转场(可选)

相关链接