取消 UIKit 交互转换后,SwiftUI 视图中的 SwiftUI 点击手势没有响应

问题描述 投票:0回答:1

我正在使用带有自定义弹出动画和交互式过渡的自定义 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)
ios swiftui uikit uinavigationcontroller
1个回答
0
投票

这似乎是由于使用变换属性将视图移出屏幕引起的,对图层上的变换执行相同操作应该是一些解决方法(或在屏幕上保留至少一点视图)

© www.soinside.com 2019 - 2024. All rights reserved.