转场与导航
问题
iOS 的页面跳转方式有哪些?如何自定义转场动画?
答案
页面跳转方式
| 方式 | 说明 | 适用场景 |
|---|---|---|
pushViewController | 入栈导航 | 详情页、列表→详情 |
present | 模态展示 | 登录、图片预览 |
UITabBarController | Tab 切换 | 底部标签栏 |
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 | 说明 |
|---|---|---|
.automatic | 13+ | 默认(通常为 pageSheet) |
.fullScreen | 2+ | 全屏覆盖 |
.pageSheet | 3.2+ | 卡片式(iOS 13+ 可下拉关闭) |
.overFullScreen | 8+ | 全屏但不移除底部 VC |
.popover | 8+ | 弹出气泡(iPad 常用) |
.custom | 7+ | 完全自定义 |
Q2: 自定义转场动画需要实现哪些协议?
答案:
UIViewControllerTransitioningDelegate:返回动画控制器和交互控制器UIViewControllerAnimatedTransitioning:定义动画内容和时长UIViewControllerInteractiveTransitioning:交互式转场(可选)