SwiftUI中如何修改fullScreenCover的转场动画?
实现FullScreenCover左侧滑入转场
SwiftUI默认的fullScreenCover依赖UIKit底层的全屏模态转场动画,直接给目标视图添加.transition(.move(edge: .leading))不会生效——这个修饰符仅作用于SwiftUI视图树内的视图插入/移除动画,而非模态视图的展示动画。要实现左侧滑入效果,需要通过桥接UIKit自定义转场动画来实现:
步骤1:创建左侧滑入的转场动画类
import UIKit class LeftSlideTransition: NSObject, UIViewControllerAnimatedTransitioning { // 设置动画时长 func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return 0.35 } // 实现滑入动画逻辑 func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { guard let toViewController = transitionContext.viewController(forKey: .to) else { return } let containerView = transitionContext.containerView // 初始状态:视图位于屏幕左侧外 toViewController.view.frame = CGRect( x: -containerView.bounds.width, y: 0, width: containerView.bounds.width, height: containerView.bounds.height ) containerView.addSubview(toViewController.view) // 执行滑入动画 UIView.animate(withDuration: transitionDuration(using: transitionContext)) { toViewController.view.frame = containerView.bounds } completion: { finished in transitionContext.completeTransition(!transitionContext.transitionWasCancelled) } } }
步骤2:自定义转场代理
class CustomTransitionDelegate: NSObject, UIViewControllerTransitioningDelegate { // 返回自定义的转场动画实例 func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { return LeftSlideTransition() } }
步骤3:封装SwiftUI视图为UIKit控制器
import SwiftUI struct CustomFullScreenCover<Content: View>: UIViewControllerRepresentable { let content: Content @Binding var isPresented: Bool private let transitionDelegate = CustomTransitionDelegate() func makeUIViewController(context: Context) -> UIHostingController<Content> { let hostingVC = UIHostingController(rootView: content) hostingVC.modalPresentationStyle = .fullScreen hostingVC.transitioningDelegate = transitionDelegate return hostingVC } func updateUIViewController(_ uiViewController: UIHostingController<Content>, context: Context) { // 同步展示状态 if isPresented, !uiViewController.isBeingPresented { context.coordinator.topVC?.present(uiViewController, animated: true) } else if !isPresented, !uiViewController.isBeingDismissed { uiViewController.dismiss(animated: true) } } func makeCoordinator() -> Coordinator { Coordinator() } class Coordinator: NSObject { // 获取当前最上层的视图控制器 var topVC: UIViewController? { UIApplication.shared.connectedScenes .compactMap { $0 as? UIWindowScene } .first?.windows .first { $0.isKeyWindow }? .rootViewController? .topMostViewController() } } } // 扩展:递归获取最上层视图控制器 extension UIViewController { func topMostViewController() -> UIViewController { if let presented = presentedViewController { return presented.topMostViewController() } return self } }
步骤4:替换原fullScreenCover使用自定义组件
struct LoginView: View { @State private var isLoginSuccess = false var body: some View { Button("登录") { isLoginSuccess = true } // 使用自定义的全屏覆盖组件 .background(CustomFullScreenCover(content: HomeView(), isPresented: $isLoginSuccess)) } } struct HomeView: View { var body: some View { ZStack { Color.blue.ignoresSafeArea() Text("首页") .font(.largeTitle) .foregroundColor(.white) } } }
点击登录按钮后,HomeView就会从左侧滑入全屏展示。
内容的提问来源于stack exchange,提问作者Supriyo Dey
相关产品推荐
相关产品推荐

