[swift]使い回しできる自前のダイアログ（アラート）を作成する

# はじめに
アプリでアラートダイアログを出す際、標準のものではなくカスタムしたダイアログを出したい場面があると思います。

ダイアログのタイトルやメッセージを自由に変えられるような汎用性の高い自前のダイアログを作成してみました。


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1112697/295c32e6-9735-6799-9b80-b9525d507798.png" width="200">

某アプリのようなダイアログも出せます。

# ソースコード

まずはベースのCustomViewを作成します

```swift:   
import UIKit

@IBDesignable
class CustomView: UIView {

    var baseView: UIView?

    /// コードから生成したときに通る初期化処理
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.commonInit()
        self.viewDidLoad()
    }

    /// InterfaceBulderで配置した場合に通る初期化処理
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.commonInit()
        self.viewDidLoad()
    }

    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        self.commonInit()
        self.viewDidLoad()
    }

    func viewDidLoad() {}

    func commonInit() {
        guard let view = UINib(nibName: String(describing: type(of: self)), bundle: Bundle(for: type(of: self))).instantiate(withOwner: self, options: nil).first as? UIView else {
            return
        }
        view.frame = self.bounds
        view.autoresizingMask = [.flexibleHeight, .flexibleWidth]
        self.addSubview(view)
        self.baseView = view
    }
}

```

そしてこいつを継承させたConfirmDialogを作成します。
これが画面に出るダイアログのViewです

```swift:   
import UIKit

final class ConfirmDialog: CustomView {
    @IBOutlet private weak var cancelButton: UIButton!
    @IBOutlet private weak var okButton: UIButton!
    @IBOutlet private weak var title: UILabel!
    @IBOutlet private weak var message: UILabel!
    @IBOutlet weak var dialogBaseView: UIView!
    
    private var okAction: (() -> Void)?
    private var cancelAction: (() -> Void)?
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        dialogBaseView.layer.cornerRadius = 5
        okButton.layer.cornerRadius = 5
        cancelButton.layer.cornerRadius = 5
    }
    
    @IBAction func tappedOkButton(_ sender: UIButton) {
        self.okAction?()
        self.removeFromSuperview()
    }
    
    @IBAction func tappedCancelButton(_ sender: UIButton) {
        self.cancelAction?()
        self.removeFromSuperview()
    }
    

    
    func set(
        title: String,
        message: String,
        okButtonTitle: String,
        cancelButtonTitle: String,
        okAction: (() -> Void)?,
        cancelAction: (() -> Void)?) {
            if title == "" {
                self.title.isHidden = true
            } else {
                self.title.text = title
            }
            self.message.text = message
            self.cancelButton.setTitle(cancelButtonTitle, for: .normal)
            self.okButton.setTitle(okButtonTitle, for: .normal)
            self.okAction = okAction
            self.cancelAction = cancelAction
        }
}


```

Xcode上だとこんな感じ

![スクリーンショット 2022-10-23 16.06.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1112697/acc42b72-93ff-0967-5a66-089a743cb682.png)

そして、UIViewControllerにExtensionしておくことですぐに呼び出すことができます。

```swift:   
import UIKit

extension UIViewController {
  /// ダイアログを呼び出す
  func showConfirmDialog(
    title: String,
    message: String,
    cancelButtonTitle: String,
    okButtonTitle: String,
    okAction: (() -> Void)? = nil,
    cancelAction: (() -> Void)? = nil
  ) {
    let confirmDialog = ConfirmDialog(frame: self.view.frame)
    confirmDialog.set(title: title, message: message, okButtonTitle: okButtonTitle, cancelButtonTitle: cancelButtonTitle, okAction: okAction, cancelAction: cancelAction)
    self.view.addSubview(confirmDialog)
  }
}

```

実際に呼び出すときの記述↓

```swift:   

import UIKit

final class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    @IBAction func tappedDialogButton(_ sender: Any) {
        // ここでダイアログを呼び出し
        self.showConfirmDialog(
            title: "サンプル", message: "これはサンプルです", cancelButtonTitle: "キャンセル", okButtonTitle: "OK",
            okAction: {
                print("OK")
            },cancelAction: {
                print("キャンセルしました")
            })
    }
}

```

タイトル、メッセージ、ボタンタイトルも自由に変更できます。
okActionとcancelActionはクロージャになっているのでタップ時の処理もそれぞれ決めることができますね。

# まとめ

使い勝手は良いと思うので、デザインなどカスタマイズしたい場合はこのようなダイアログを作成すると楽だと思いました。

ソースはGitHubに上げております↓↓
https://github.com/taro-ken/CustomViewSample