Posted at

背景透過なViewControllerをクロスディゾルブでモーダル表示

More than 3 years have passed since last update.

iOS 7とiOS 8でやり方が違うので実は結構面倒だったりする。


  • iOS 7は遷移元のViewControllerに対してごにょごにょ

  • iOS 8は遷移先のViewControllerに対してごにょごにょ


iOS 7の場合


モーダルを出す時

modalPresentationStyle = .CurrentContext

modalTransitionStyle = .CrossDissolve
navigationController?.modalPresentationStyle = .CurrentContext
navigationController?.modalTransitionStyle = .CrossDissolve

presentViewController(controller, animated: animated, completion: {
[weak self] () -> Void in

// 遷移が終わったら元の状態に戻す。モーダルから戻ってきた後に別のモーダルを出そうとしてクロスディゾルブのままだったりする
self?.modalPresentationStyle = .FullScreen
self?.modalTransitionStyle = .CoverVertical
self?.navigationController?.modalPresentationStyle = .FullScreen
self?.navigationController?.modalTransitionStyle = .CoverVertical
})


モーダルを閉じる時

modalPresentationStyle = .CurrentContext

modalTransitionStyle = .CrossDissolve
navigationController?.modalPresentationStyle = .CurrentContext
navigationController?.modalTransitionStyle = .CrossDissolve

dismissViewControllerAnimated(true, completion: nil)


iOS 8の場合


モーダルを出す時

controller.modalPresentationStyle = .OverCurrentContext

controller.modalTransitionStyle = .CrossDissolve
presentViewController(controller, animated: animated, completion: nil)


モーダルを閉じる時

presentingViewController?.modalPresentationStyle = .OverCurrentContext

presentingViewController?.modalTransitionStyle = .CrossDissolve

// completionの中で、self?.presentingViewController とやってもnilなので
let p = presentingViewController

dismissViewControllerAnimated(true, completion: {
[weak self] () -> Void in

p?.modalPresentationStyle = .FullScreen
p?.modalTransitionStyle = .CoverVertical
})


まとめると


モーダルを出す時

if iOS8以上 {

controller.modalPresentationStyle = .OverCurrentContext
controller.modalTransitionStyle = .CrossDissolve
} else {
modalPresentationStyle = .CurrentContext
modalTransitionStyle = .CrossDissolve
navigationController?.modalPresentationStyle = .CurrentContext
navigationController?.modalTransitionStyle = .CrossDissolve
}

presentViewController(controller, animated: animated, completion: {
[weak self] () -> Void in

if iOS8以上 { return }

self?.modalPresentationStyle = .FullScreen
self?.modalTransitionStyle = .CoverVertical
self?.navigationController?.modalPresentationStyle = .FullScreen
self?.navigationController?.modalTransitionStyle = .CoverVertical
})


モーダルを閉じる時

if iOS8以上 {

presentingViewController?.modalPresentationStyle = .OverCurrentContext
presentingViewController?.modalTransitionStyle = .CrossDissolve
} else {
modalPresentationStyle = .CurrentContext
modalTransitionStyle = .CrossDissolve
navigationController?.modalPresentationStyle = .CurrentContext
navigationController?.modalTransitionStyle = .CrossDissolve
}

let p = presentingViewController

dismissViewControllerAnimated(true, completion: {
[weak self] () -> Void in

if iOS8以上 {
p?.modalPresentationStyle = .FullScreen
p?.modalTransitionStyle = .CoverVertical
}
})


やってられるか!!

というわけで、以下のようなextensionを用意する。


UIViewController+Extensions.swift

extension UIViewController {

enum Transition {
case Default, CrossDissolve
}

func tak_presentViewController(controller: UIViewController, animated: Bool, transition: Transition) {
tak_presentViewController(controller, animated: animated, transition: transition, completion: nil)
}

func tak_presentViewController(controller: UIViewController, animated: Bool, transition: Transition, completion: (Void -> Void)?) {
if iOS8以上 {
controller.tak_setupTransition(transition)
} else {
tak_setupTransitionForIos7(transition)
}

presentViewController(controller, animated: animated, completion: {
[weak self] () -> Void in

if iOS8以上 { return }

self?.tak_setupTransitionForIos7(.Default)
completion?()
})
}

func tak_dismissViewControllerAnimated(animated: Bool, transition: Transition) {
tak_dismissViewControllerAnimated(animated, transition: transition, completion: nil)
}

func tak_dismissViewControllerAnimated(animated: Bool, transition: Transition, completion: (Void -> Void)?) {
if iOS8以上 {
presentingViewController?.tak_setupTransition(transition)
} else {
tak_setupTransitionForIos7(transition)
}

// completionの中で、self?.presentingViewController とやってもnilなので
let p = presentingViewController

dismissViewControllerAnimated(true, completion: {
[weak self] () -> Void in

if iOS8以上 {
p?.tak_setupTransition(.Default)
}

completion?()
})
}

// iOS7用
private func tak_setupTransitionForIos7(transition: Transition) {
switch transition {
case .Default:
modalPresentationStyle = .FullScreen
modalTransitionStyle = .CoverVertical
case .CrossDissolve:
modalPresentationStyle = .CurrentContext
modalTransitionStyle = .CrossDissolve
}
navigationController?.tak_setupTransitionForIos7(transition)
}

private func tak_setupTransition(transition: Transition) {
switch transition {
case .Default:
modalPresentationStyle = .FullScreen
modalTransitionStyle = .CoverVertical
case .CrossDissolve:
modalPresentationStyle = .OverCurrentContext
modalTransitionStyle = .CrossDissolve
}
}
}



モーダルを出す時

tak_presentViewController(c, animated: true, transition: .CrossDissolve)


モーダルを閉じる時

tak_dismissViewControllerAnimated(animated: true, transition: .CrossDissolve)