Posted at
CocoaDay 5

[iOS] Xibを使って自前のダイアログを作る

More than 1 year has passed since last update.


きっかけ

Androidとおなじにしてよ。っていわれたのが最初のきっかけです。

IDやパスワードを入力したり、カスタマイズがしやすいようにXibでAlertViewが簡単に作れるといいなと思いました。

今までこんな書き方をよく使ってましたが

self.presentViewController(vc, animated: true, completion: nil)



Viewを上に重ねるだけでなく、Alertっぽくしたい!!っていうのが一番の希望。


でも

でも、実際Alertなわけではなく、ViewControllerをAlertっぽくみせているだけです


プロジェクトを作る


シングルビューアプリケーションでプロジェクトを作ります

ss00.png


プロジェクト名を入力します

ss02.png


Alertに使うViewControllerを作ります


メニューからFile-New-FileでCocoa Touch Classを選択します。

ss01.png


ViewControllerの名前をつけます

*Also create XIB fileにチェックをつけます

ss03.png


出来上がったMyAlertViewController.swiftを修正します

*画面遷移のアニメーションをカスタマイズするのでUIViewControllerTransitioningDelegateを追加します

ss04.png


外観のカスタマイズ

MyAlertViewController.Xibにボタンをつけたり、タイトルをつけてMyAlertViewController.swiftとOutletで結んでください。

ss06.png


MyAlertViewController.swiftを編集


3つのinit

1.xibを初期化するinit。背景を透明にしたり、アニメーションをカスタマイズする設定をします


MyAlertViewController.swift

override init(nibName nibNameOrNil:String?, bundle ninBundleOrNil:Bundle? ){

super.init(nibName:nibNameOrNil,bundle:ninBundleOrNil)
self.transitioningDelegate = self
self.providesPresentationContextTransitionStyle = true
self.definesPresentationContext = true
self.modalPresentationStyle = .custom

}


2.実際に使用する初期化処理です


MyAlertViewController.swift

    convenience init(title:String,desc:String){

self.init(nibName:"MyAlertViewController",bundle:nil)
titleText = title
messageText = desc
}

3.普通のinitは使わないのでエラーにします


MyAlertViewController.swift

    required init?(coder aDecider: NSCoder){

fatalError("init error")
}


UIViewControllerTransitioningDelegate

デフォルトのアニメーションだと画面下から上に移動するアニメーションなので書き換えます


MyAlertViewController.swift

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

return AlertAnimation(show:true)
}
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return AlertAnimation(show:false)
}


アニメーションの実態を書きます


class MyAlertViewController: UIViewController,UIViewControllerTransitioningDelegate {


の最後の括弧「}」が閉じてから下に付け足すか、もしくは別ファイルにしてください


MyAlertViewController.swift

class AlertAnimation : NSObject, UIViewControllerAnimatedTransitioning {

let show: Bool

init(show: Bool) {
self.show = show
}
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
if (show) {
return 0.45
} else {
return 0.25
}
}

func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
if (show) {
self.presentAnimateTransition(transitionContext: transitionContext)
} else {
self.dismissAnimateTransition(transitionContext: transitionContext)
}
}

func presentAnimateTransition(transitionContext: UIViewControllerContextTransitioning) {

let alertVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to) as! MyAlertViewController
alertVC.view.frame = UIScreen.main.bounds
let containerView = transitionContext.containerView
alertVC.alertView.alpha = 0.0
alertVC.alertView.center = alertVC.view.center
alertVC.alertView.transform = CGAffineTransform.init(scaleX: 0.5, y: 0.5)
containerView.addSubview(alertVC.view)

UIView.animate(withDuration: 0.25,
animations: {
alertVC.view.alpha = 1.0
alertVC.alertView.alpha = 1.0
alertVC.alertView.transform = CGAffineTransform.init(scaleX: 1.05, y:1.05)
},
completion: { finished in
UIView.animate(withDuration:0.2,
animations: {
alertVC.alertView.transform = CGAffineTransform.identity
},
completion: { finished in
if (finished) {
transitionContext.completeTransition(true)
}
})
})
}
func dismissAnimateTransition(transitionContext: UIViewControllerContextTransitioning) {

let alertVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from) as! MyAlertViewController

UIView.animate(withDuration:self.transitionDuration(using: transitionContext),
animations: {
alertVC.view.alpha = 0.0
alertVC.alertView.alpha = 0.0
alertVC.alertView.transform = CGAffineTransform.init(scaleX: 0.9, y: 0.9)
},
completion: { finished in
transitionContext.completeTransition(true)
})
}
}



ソース

GitHubにおきました