代码之家  ›  专栏  ›  技术社区  ›  Nicolas Miari

模糊不清的背景模式导航控制器,在推送动画时无缝?

  •  0
  • Nicolas Miari  · 技术社区  · 6 年前

    我用一个表视图控制器作为根节点来演示一个导航控制器,当用户点击一个单元格时,我会推送更多的视图控制器。现在,我想对整个事情应用模糊/振动效果。

    情节提要如下所示:

    enter image description here

    现在,要将模糊效果应用于 整个导航控制器 ,以便可以在下面看到初始视图控制器中的图像。

    我成功地将相同的模糊效果应用于“表视图”控制器和“局部视图”控制器,如下所示:

    class TableViewController: UITableViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            self.tableView.tableFooterView = UIView(frame: .zero)
    
            tableView.backgroundColor = UIColor.clear
            let blurEffect = UIBlurEffect(style: .dark)
            let blurEffectView = UIVisualEffectView(effect: blurEffect)
            tableView.backgroundView = blurEffectView
            tableView.separatorEffect = UIVibrancyEffect(blurEffect: blurEffect)
        }
    }
    

    局部视图控制器

    class DetailViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            view.backgroundColor = .clear
            let blurEffect = UIBlurEffect(style: .dark)
            let blurView = UIVisualEffectView(effect: blurEffect)
            blurView.translatesAutoresizingMaskIntoConstraints = false
            view.insertSubview(blurView, at: 0)
            NSLayoutConstraint.activate([
                blurView.heightAnchor.constraint(equalTo: view.heightAnchor),
                blurView.widthAnchor.constraint(equalTo: view.widthAnchor),
            ])
        }
    }
    

    .overFullScreen )

    然而, 在导航过渡到局部视图控制器的最后, 令人讨厌的艺术品

    enter image description here

    我认为这与ios7以来,推送视图控制器不能有透明的背景有关,否则推送视图控制器在过渡结束时会被立即移除。

    我尝试将模糊效果应用于导航控制器,并使两个孩子的视图都透明,但看起来也不太好。

    2 回复  |  直到 6 年前
        1
  •  1
  •   ChintaN -Maddy- Ramani    6 年前

    尝试以下步骤。我没试过,但应该有用。

    1. didFinishLaunchingWithOptions 并在默认情况下隐藏它。
    2. 将相同的图像添加到视图控制器中。
    3. 所以当你呈现时,它会显示进入模态视图控制器的图像。
    4. 完成后,取消隐藏窗口图像和隐藏视图控制器图像。
    5. 单击“上一步”按钮关闭视图时,首先取消隐藏视图控制器图像并隐藏窗口图像。所以你的动画看起来很正常。

    如果你需要帮助,请告诉我。

        2
  •  1
  •   Nicolas Miari    6 年前

    我在问题中发现, 自iOS 7以来推出的推送/弹出动画转换

    UINavigationControllerDelegate ,更准确地说是方法: navigationController(_:animationControllerFor:from:to:) 从根本上复制UINavigationController的动画转换。

    这允许我添加一个 mask view 到在推送操作期间转换离开的视图,以便剪裁参考底图部分,并且不会出现可见的瑕疵。

    操作(最终,我也要做pop操作,还有基于pop的交互式切换形式swipe手势), 我做了个习惯 UINavigationController 子类 ,和 put it on GitHub .

    可归结为以下步骤:

    1. 首先,转换 .to 右侧视图,屏幕外。在动画中,逐渐将其变换回标识(屏幕中心)。
    2. 设置 作为 mask .from 视图,初始边界等于 视图(无遮罩)。在动画中,逐渐减小遮罩的宽度 frame 属性设置为其初始值的一半。
    3. 在动画中,逐渐平移 from

    class AnimationController: NSObject, UIViewControllerAnimatedTransitioning {
    
        // Super slow for debugging:
        let duration: TimeInterval = 1
    
        func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
            return duration
        }
    
        func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
            guard let fromView = transitionContext.view(forKey: .from) else {
                return
            }
            guard let toView = transitionContext.view(forKey: .to) else {
                return
            }
            guard let toViewController = transitionContext.viewController(forKey: .to) else {
                return
            }
    
            //
            // (Code below assumes navigation PUSH operation. For POP, 
            //  use similar code but with view roles and direction 
            //  reversed)
            //
    
            // Add target view to container:
            transitionContext.containerView.addSubview(toView)
    
            // Set tagret view frame, centered on screen
            let toViewFinalFrame = transitionContext.finalFrame(for: toViewController)
            toView.frame = toViewFinalFrame
            let containerBounds = transitionContext.containerView.bounds
            toView.center = CGPoint(x: containerBounds.midX, y: containerBounds.midY)
    
            // But translate it to fully the RIGHT, for now:
            toView.transform = CGAffineTransform(translationX: containerBounds.width, y: 0)
    
            // We will slide the source view out, to the LEFT, by half as much:
            let fromTransform = CGAffineTransform(translationX: -0.5*containerBounds.width, y: 0)
    
            // Apply a white UIView as mask to the source view:
            let maskView = UIView(frame: CGRect(origin: .zero, size: fromView.frame.size))
            maskView.backgroundColor = .white
            fromView.mask = maskView
    
            // The mask will shrink to half the width during the animation:
            let maskViewNewFrame = CGRect(origin: .zero, size: CGSize(width: 0.5*fromView.frame.width, height: fromView.frame.height))
    
            // Animate:
            UIView.animate(withDuration: duration, delay: 0, options: [.curveEaseOut], animations: {
    
                fromView.transform = fromTransform // off-screen to the left (half)
    
                toView.transform = .identity // Back on screen, fully centered
    
                maskView.frame = maskViewNewFrame // Mask to half width
    
            }, completion: {(completed) in
    
                // Remove mask, or funny things will happen to a 
                // table view or scroll view if the user 
                // "rubber-bands":
                fromView.mask = nil
    
                transitionContext.completeTransition(completed)
            })
        }
    

    enter image description here

    (为了清晰起见,我在局部视图控制器中添加了一个文本视图)