iOSに元々ついているアラートビューじゃなくてデザインをカスタマイズしたビューを使いたい! でもコードは変えたくないという人のためのTips
デザインの対象
以下のようなUIAlertControllerの.Alertスタイル 【Swift】アラートを表示する(Alert/ActionSheet)
let alert: UIAlertController = UIAlertController(title: "アラート表示", message: "保存してもいいですか?", preferredStyle: UIAlertControllerStyle.Alert) let defaultAction: UIAlertAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler:{ (action: UIAlertAction!) -> Void in print("OK") }) let cancelAction: UIAlertAction = UIAlertAction(title: "キャンセル", style: UIAlertActionStyle.Cancel, handler:{ (action: UIAlertAction!) -> Void in print("Cancel") }) alert.addAction(cancelAction) alert.addAction(defaultAction) presentViewController(alert, animated: true, completion: nil)
基本的には上の形でコンストラクタの名前のみ変えることで実現することを目指します。
iOSアプリではviewControllerに対してストーリーボードでUIを作っていくことが一般的ですが、コード上でstoryboardを用いた画面の遷移は該当となるstoryboardのインスタンスを作成するので上記のコードでは不可能です。また、上記のコードではライフサイクル変わるため、クロージャの参照が変わります。
なのでxibとviewControllerを結びつけることで、実現します。
その際にxibとviewControllerの紐付けを行うことでstoryboardと同様にUIの編集が行えるようになります。 ViewControllerとxibのひもづけを手動で行う
あとはUIAlertAction,UIAlertControllerの新しいクラスを作成するだけです。
import UIKit enum CustomAlertControllerAction { case Cancel case Default case Destructive } enum CustomAlertControlerStyle { case Alert } class CustomAlertAction : NSObject { var handler: ((action: CustomAlertAction)->())? var style:CustomAlertControllerAction var title:String? init(title: String?, style: CustomAlertControllerAction, handler: ((action: CustomAlertAction) -> ())?){ self.handler = handler self.style = style if let title = title{ self.title = title } } } class CustomAlertController: UIViewController { //UIの設定 ボタンはキャンセルとOKの二つ @IBOutlet weak var alertMaskBackGround: UIImageView! @IBOutlet weak var titleLabel: UILabel! @IBOutlet weak var messageLabel: UILabel! @IBOutlet weak var acceptButton: UIButton! @IBOutlet weak var cancelButton: UIButton! @IBOutlet weak var panelView: UIView! var actions = [CustomAlertAction]() //MARK: - Initialiser internal convenience init(title: String, message: String, preferredStyle: CustomAlertControlerStyle) { self.init() let nib = loadNibAlertController() if nib != nil{ self.view = nib![0] as! UIView } //値の挿入 acceptButton.addTarget(self, action: #selector(acceptButtonTapped), forControlEvents: .TouchUpInside) cancelButton.addTarget(self, action: #selector(cancelButtonTapped), forControlEvents: .TouchUpInside) } private func loadNibAlertController() -> [AnyObject]?{ let podBundle = NSBundle(forClass: self.classForCoder) if let bundleURL = podBundle.URLForResource("CustomAlertView", withExtension: "bundle") { if let bundle = NSBundle(URL: bundleURL) { return bundle.loadNibNamed("CustomAlertView", owner: self, options: nil) } else { assertionFailure("Could not load the bundle") } } else if let nib = podBundle.loadNibNamed("CustomAlertView", owner: self, options: nil) { return nib } else{ assertionFailure("Could not create a path to the bundle") } return nil } func addAction(action:CustomAlertAction){ actions.append(action) } func acceptButtonTapped() { dismissViewControllerAnimated(true, completion: nil) for action in actions{ if action.style == .Default || action.style == .Destructive{ if let handler = action.handler{ handler(action: action) } } } } func cancelButtonTapped() { dismissViewControllerAnimated(true, completion: nil) for action in actions{ if action.style == .Cancel{ if let handler = action.handler{ handler(action: action) } } } } }