web-dev-qa-db-ja.com

ぼかし効果のあるViewControllerの提示

背景をぼかす効果のあるビューコントローラーをモーダルに表示しています。 iOS 10/XCode8でアニメーションに問題が発生しました。これはプレゼンテーションコードです:

_let modalVC = ModalViewController(nibName: "ModalViewController", bundle: nil)
modalVC.modalTransitionStyle = .CrossDissolve
modalVC.modalPresentationStyle = .OverFullScreen
presentViewController(modalVC, animated: true, completion: nil)
_

ModalViewControllerのviewDidLoad()関数にぼかしを追加します。

_let blurEffect = UIBlurEffect(style: .Light)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
blurEffectView.frame = view.bounds
blurEffectView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]

view.addSubview(blurEffectView)
view.sendSubviewToBack(blurEffectView)
_

ModalViewControllerの背景ははっきりしていて、ダークブラー効果のあるBlurEffectViewを追加しました。前のスニペットとInterfaceBuilderの両方でプログラムで試しました。

IOS 8および9では、_.CrossDissolve_トランジションが「フェード」を処理しましたが、iOS 10(デバイスとシミュレーターの両方)でテストした後、ビューはぼやけではなく暗い半透明の背景色で表示されます。

_.CrossDissolve_アニメーションが終了すると、背景色が実際のぼかし効果の背景に変わります。なぜこれが起こっているのか考えはありますか?

また、運が悪かったので、モーダルビューコントローラのlayoutIfNeeded()の最初と最後にviewDidLoad()を追加してみました。私はSwift 2.3を使用しています

11
Fdo

新しいUIViewControllerAnimatedTransitioningを作成する必要があります。

次に、animateTransition(using transitionContext: UIViewControllerContextTransitioning)でアニメーションをコーディングする必要があります。

IOS 10では、UIViewPropertyAnimatorBlurRadiusをアニメーション化するためにUIVisualBlurEffectを使用できるようになりました。

結果: enter image description here

ここに使用例があります: https://github.com/PierrePerrin/PPBlurModalPresentation

最初

ぼかし遷移を作成する必要があります

    class BlurModalPresentation: NSObject,UIViewControllerAnimatedTransitioning {


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

            return 0.5
        }

//This is the blur view used for transition
        var blurView = UIVisualEffectView(effect: UIBlurEffect(style: UIBlurEffectStyle.light))
        var destinationView : UIView!
        var animator: UIViewPropertyAnimator?

        // This method can only  be a nop if the transition is interactive and not a percentDriven interactive transition.
        func animateTransition(using transitionContext: UIViewControllerContextTransitioning){

            let containerView = transitionContext.containerView

            _ = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)
            let toVc = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)

            destinationView = toVc!.view
            destinationView.alpha = 0.0

//Here we add the blur view and set it effect to nil
            blurView.effect = nil
            blurView.frame = containerView.bounds

            self.blurTransition(transitionContext) { 

                self.unBlur(transitionContext, completion: { 

                    self.blurView.removeFromSuperview()
                    transitionContext.completeTransition(true)
                })
            }

            containerView.addSubview(toVc!.view)
            containerView.addSubview(blurView)
        }

        //This methods add the blur to our view and our destinationView
        func blurTransition(_ context : UIViewControllerContextTransitioning,completion: @escaping () -> Void){

            UIViewPropertyAnimator.runningPropertyAnimator(withDuration: self.transitionDuration(using: context)/2, delay: 0, options: UIViewAnimationOptions.curveLinear, animations: {

                self.destinationView.alpha = 0.5
                  self.blurView.effect = UIBlurEffect(style: UIBlurEffectStyle.light)
            }, completion: { (position) in
                completion()
            })

        }
        //This Method remove the blur view with an animation
        func unBlur(_ context : UIViewControllerContextTransitioning,completion: @escaping () -> Void){

            UIViewPropertyAnimator.runningPropertyAnimator(withDuration: self.transitionDuration(using: context) / 2, delay:0, options: UIViewAnimationOptions.curveLinear, animations: {

                self.destinationView.alpha = 1.0
                self.blurView.effect = nil
            }, completion: { (position) in
                completion()
            })
        }

    }

次に

ViewControllerで移行する委任を設定する必要があります。

import UIKit

class ViewController: UIViewController,UIViewControllerTransitioningDelegate {

    let blurModalPresentation = BlurModalPresentation()

    override func viewDidLoad() {
        super.viewDidLoad()

    }

    func showVC(){

        let str = self.storyboard!
        let vc = str.instantiateViewController(withIdentifier: "YourViewControllerIdentifier")
        vc.transitioningDelegate = self
        self.present(vc, animated: true, completion: nil)
    }


    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
    }

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

        return blurModalPresentation
    }


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

        return blurModalPresentation
    }

}
10
Pierre Perrin

まず、この新たに導入された動作はバグであり、将来のアップデートで修正されると想定する必要があるため、このソリューションを一時的な回避策と見なしています。これにより、アニメーションの後でではなくアニメーション中にぼかし効果が現れるため、少し目立たなくなります。それでもiOS9以降ほど良くはありませんが、少し良くなっています。

  1. アニメーションなしの現在のViewController:

    presentViewController(modalVC, animated: false, completion: nil)
    
  2. 最初からビューを非表示にします。

    override func viewDidLoad() {
        super.viewDidLoad()
    
        view.alpha = 0
    }
    
  3. アニメーションを手動で適用します。

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
    
        UIView.animateWithDuration(0.25) {
            self.view.alpha = 1
        }
    }
    
    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)
    
        UIView.animateWithDuration(0.25) {
            self.view.alpha = 0
        }
    }
    
1
Johannes

唯一の正しい方法は、カスタムのモーダルトランジションを作成してエフェクトプロパティをアニメーション化することです。 https://stackoverflow.com/a/3970974 を参照してください

1
janmisar