我正在使用带有自定义弹出动画和交互式过渡的自定义 UINavigationController。自定义导航控制器适用于标准 UIKit 视图控制器。但是,当我推送托管 SwiftUI 视图的 UIHostingController 时,如果取消交互转换,SwiftUI 视图将变得对点击手势无响应。该问题似乎特别发生在交互式转换开始然后取消之后。
这是交互式转换代码
class CustomPopAnimator: NSObject, UIViewControllerAnimatedTransitioning {
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.3
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let containerView = transitionContext.containerView
guard let fromView = transitionContext.view(forKey: .from),
let toView = transitionContext.view(forKey: .to) else {
return
}
containerView.insertSubview(toView, belowSubview: fromView)
let screenWidth = UIScreen.main.bounds.width
toView.transform = CGAffineTransform(translationX: -screenWidth / 3, y: 0)
UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: {
fromView.transform = CGAffineTransform(translationX: screenWidth, y: 0)
toView.transform = .identity
}) { finished in
fromView.transform = .identity
toView.transform = .identity
fromView.isUserInteractionEnabled = true
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
}
}
}
class CustomInteractiveTransition: UIPercentDrivenInteractiveTransition {
var hasStarted = false
var shouldFinish = false
override func cancel() {
super.cancel()
reset()
}
override func finish() {
super.finish()
reset()
}
private func reset() {
hasStarted = false
shouldFinish = false
}
}
@objc
class CustomNavigationController: UINavigationController, UINavigationControllerDelegate {
private let customAnimator = CustomPopAnimator()
private let customInteractiveTransition = CustomInteractiveTransition()
override func viewDidLoad() {
super.viewDidLoad()
delegate = self
setupGesture()
}
private func setupGesture() {
let edgeSwipeGesture = UIScreenEdgePanGestureRecognizer(target: self, action: #selector(handleEdgeSwipe(_:)))
edgeSwipeGesture.edges = .left
view.addGestureRecognizer(edgeSwipeGesture)
}
@objc private func handleEdgeSwipe(_ gesture: UIScreenEdgePanGestureRecognizer) {
let translation = gesture.translation(in: view)
let progress = translation.x / view.bounds.width
switch gesture.state {
case .began:
customInteractiveTransition.hasStarted = true
popViewController(animated: true)
case .changed:
customInteractiveTransition.shouldFinish = progress > 0.5
customInteractiveTransition.update(progress)
case .ended:
customInteractiveTransition.hasStarted = false
customInteractiveTransition.shouldFinish ? customInteractiveTransition.finish() : customInteractiveTransition.cancel()
case .cancelled:
customInteractiveTransition.hasStarted = false
customInteractiveTransition.cancel()
default:
break
}
}
func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return operation == .pop ? customAnimator : nil
}
func navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
return customInteractiveTransition.hasStarted ? customInteractiveTransition : nil
}
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
if let hostingController = viewController as? AIMAHostingController<SwiftUIView> {
DispatchQueue.main.async {
hostingController.view.setNeedsLayout()
hostingController.view.layoutIfNeeded()
}
}
}
}
SwiftUI 代码
import SwiftUI
struct SwiftUIView: View {
var body: some View {
VStack {
Spacer()
Text("Hello, World!")
.id("123")
.background(Color.green)
.padding()
.onTapGesture {
print("===onclick")
}
Spacer()
}
}
}
let hostingController = UIHostingController(rootView: SwiftUIView())
navigationController?.pushViewController(hostingController, animated: true)
这似乎是由于使用变换属性将视图移出屏幕引起的,对图层上的变换执行相同操作应该是一些解决方法(或在屏幕上保留至少一点视图)