【问题标题】:View being blocked by UITransitionView after being presented呈现后被 UITransitionView 阻止的视图
【发布时间】:2016-03-21 22:09:59
【问题描述】:

我有一个侧面导航控制器并通过 UIButton 呈现它。当我通过[self presentviewcontroller: NC animated: YES completion: nil] 直接将此 NC 设置为根视图控制器时,出于某种原因,NC 的菜单侧被 UITransitionView 阻止,我无法消失。

我附上了一张 的图片。 是另一个。

我尝试了以下方法:

UIWindow *window = [(AppDelegate *)[[UIApplication sharedApplication] delegate] window];
    window.backgroundColor = kmain;


    CATransition* transition = [CATransition animation];
    transition.duration = .5;
    transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    transition.type = kCATransitionPush;
    transition.subtype = kCATransitionFromTop;

    [nc.view.layer addAnimation:transition forKey:kCATransition];

    [UIView transitionWithView:window
                      duration:0.5
                       options:UIViewAnimationOptionTransitionNone
                    animations:^{ window.rootViewController = nc; }
                    completion:^(BOOL finished) {
                        for (UIView *subview in window.subviews) {
                            if ([subview isKindOfClass:NSClassFromString(@"UITransitionView")]) {
                                [subview removeFromSuperview];
                            }
                        }
                    }];

但它非常hacky,并且随着窗口的rootviewcontroller在转换过程中发生变化,它有点波涛汹涌,导航控制器和右上角的一部分变黑了。看起来很糟糕。

【问题讨论】:

  • 找到根本原因了吗?我在这里遇到了同样的问题。删除视图或禁用视图上的触摸似乎是一种解决方法,但我们如何避免它呢?我不明白为什么会出现。
  • 很久以前我不太确定,但我相信我完全切换了库并使用了 JASidePannelController:github.com/gotosleep/JASidePanels 更容易使用。

标签: ios uiviewcontroller uinavigationcontroller uiviewanimationtransition catransition


【解决方案1】:

要通过UITransitionView 获取点击事件,请将containerViewuserInteractionEnabled 设置为false。如果您正在使用 UIViewControllerAnimatedTransitioning 来制作自定义过渡动画,则可以这样做。

例如,在您的animateTransition(_:)

func animateTransition(transitionContext: UIViewControllerContextTransitioning) {

    let containerView = transitionContext.containerView
    containerView.isUserInteractionEnabled = false

    ...
}

【讨论】:

  • 如果我将 containerView 的交互设置为禁用,则显示的视图上的点击也会失败。
  • 有什么解决办法吗?
  • @Alper 这是解决方法:stackoverflow.com/a/63497131/4833705
【解决方案2】:

在我的情况下,我需要一个 halfSize 视图控制器。我关注了this answer which worked great,直到我意识到我仍然需要能够与呈现的 vc(halfSizeVC 后面的 vc)进行交互。

关键是你必须将这两个帧设置为相同的 CGRect 值:

halfSizeVC.frame = CGRect(x: 0, y: UIScreen.main.bounds.height / 2, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)

containerView = CGRect(x: 0, y: UIScreen.main.bounds.height / 2, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)

这是从 ViewControllerHalfSizeController 并使 HalfSizeController 屏幕大小为 1/2 的代码。即使在屏幕上显示halfSizeVC您仍然可以与 其后面的 vc 的上半部分进行交互。

如果您希望能够触摸 halfSizeVC 内部的某些东西,您还必须创建一个 PassthroughView 类。我把它放在了底部。

呈现的 vc 是白色的,底部有一个紫色按钮。点击紫色按钮会弹出红色 halfSizeVC。

vc/presentingVC:

import UIKit

class ViewController: UIViewController {

    lazy var purpleButton: UIButton = {
        let button = UIButton(type: .system)
        button.translatesAutoresizingMaskIntoConstraints = false
        button.setTitle("Tap to Present HalfSizeVC", for: .normal)
        button.setTitleColor(UIColor.white, for: .normal)
        button.backgroundColor = UIColor.systemPurple
        button.addTarget(self, action: #selector(purpleButtonPressed), for: .touchUpInside)
        button.layer.cornerRadius = 7
        button.layer.masksToBounds = true
        return button
    }()

    var halfSizeVC: HalfSizeController?

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white

        // tap gesture on vc will dismiss HalfSizeVC
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissHalfSizeVC))
        view.addGestureRecognizer(tapGesture)
    }


    // tapping the purple button presents HalfSizeVC
    @objc func purpleButtonPressed() {

        halfSizeVC = HalfSizeController()

        // *** IMPORTANT ***
        halfSizeVC!.view.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height / 2)

        halfSizeVC!.modalPresentationStyle = .custom

        present(halfSizeVC!, animated: true, completion: nil)
    }

    // dismiss HalfSizeVC by tapping anywhere on the white background
    @objc func dismissHalfSizeVC() {

        halfSizeVC?.dismissVC()
    }
}

halfSizeVC/presentedVC

import UIKit

class HalfSizeController: UIViewController {

    init() {
        super.init(nibName: nil, bundle: nil)
        modalPresentationStyle = .custom
        transitioningDelegate = self
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    lazy var topHalfDummyView: PassthroughView = {
        let view = PassthroughView()
        view.translatesAutoresizingMaskIntoConstraints = false
        view.backgroundColor = .clear
        view.isUserInteractionEnabled = true
        return view
    }()

    var isPresenting = false
    let halfScreenHeight = UIScreen.main.bounds.height / 2

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .red

        setAnchors()
    }

    private func setAnchors() {
    
        view.addSubview(topHalfDummyView)
        topHalfDummyView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
        topHalfDummyView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        topHalfDummyView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
        topHalfDummyView.heightAnchor.constraint(equalToConstant: halfScreenHeight).isActive = true
    }

    public func dismissVC() {
        dismiss(animated: true, completion: nil)
    }
}

extension HalfSizeController: UIViewControllerTransitioningDelegate, UIViewControllerAnimatedTransitioning {

    func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return self
    }

    func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return self
    }

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

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {

        let containerView = transitionContext.containerView

        // *** IMPORTANT ***
        containerView.frame = CGRect(x: 0, y: halfScreenHeight, width: UIScreen.main.bounds.width, height: halfScreenHeight)

        let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)
        guard let toVC = toViewController else { return }
        isPresenting = !isPresenting

        if isPresenting == true {
            containerView.addSubview(toVC.view)

            topHalfDummyView.frame.origin.y += halfScreenHeight

            UIView.animate(withDuration: 0.4, delay: 0, options: [.curveEaseOut], animations: {

                self.topHalfDummyView.frame.origin.y -= self.halfScreenHeight

            }, completion: { (finished) in
                transitionContext.completeTransition(true)
            })

        } else {
            UIView.animate(withDuration: 0.4, delay: 0, options: [.curveEaseOut], animations: {
            
            }, completion: { (finished) in
                self.topHalfDummyView.frame.origin.y += self.halfScreenHeight
                transitionContext.completeTransition(true)
            })
        }
    }
}

HalfSizeVC 中的 topHalfDummyView 需要 PassthroughView

import UIKit

class PassthroughView: UIView {
    
    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        print("Passing all touches to the next view (if any), in the view stack.")
        return false
    }
}

按下紫色按钮之前:

按下紫色按钮后:

如果你按下白色背景,红色会消失

您只需 c+p 所有 3 个文件并运行您的项目

【讨论】:

  • 这应该是一个可接受的答案
【解决方案3】:

我遇到了类似的问题,即 UITransitionView 一直阻止我的视图,阻止任何用户交互。

在我的情况下,这是由于未完成的自定义动画 UIViewController 转换。

我忘记正确完成我的转换:

TransitionContext.completeTransition(transitionContext.transitionWasCancelled)

TransitionContext.completeTransition(!transitionContext.transitionWasCancelled)

func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {}

来自UIViewControllerAnimatedTransitioning 协议

【讨论】:

    【解决方案4】:

    我遇到了同样的问题,但在一个稍微不同的场景中,我最终做了一些非常相似的事情来找到视图,但我没有删除可能更成问题的视图,而是禁用了用户交互,所以任何触摸事件都会抛出它任何其他对象都可以处理用户的交互。 在我的情况下,这只是在将应用程序更新到 iOS 10 后才出现,在 iOS 9 中运行的相同代码不属于这种情况。

    【讨论】:

      【解决方案5】:

      我遇到了同样的问题,这个问题为我解决了,

      navigationController.setNavigationBarHidden(true, animated: false)

      这对我有用,因为我在视图控制器中拥有自定义视图作为导航栏。

      【讨论】:

        【解决方案6】:

        我在弹出视图控制器上设置accessibilityElements 时遇到了这个问题。我通过删除分配元素数组来修复它。

        【讨论】:

          猜你喜欢
          • 2017-04-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-04-10
          • 2013-09-22
          • 2020-08-27
          • 2011-08-06
          相关资源
          最近更新 更多