【Swift】UIAlertControllerのactionSheetにカスタムViewを埋め込む

2022.11.29

UIAlertControllerからactionSheetスタイルで表示したアラートにカスタムViewを埋め込みたくなったので、埋め込み方法を調べました。

環境

  • Xcode 14.1
  • iOS 16.1

UIAlertController.Style.actionSheet

UIAlertController.Style.actionSheetに選択することでiOSデバイスでは下から出てくるアクションシートを表現出来ます。

@IBAction private func showActionSheet(_ sender: UIButton) {
    let actionSheet = UIAlertController(title: "かわいいは作れる", message: nil,
                                        preferredStyle: .actionSheet)

    // iPadのクラッシュ対応
    actionSheet.popoverPresentationController?.sourceView = sender.superview
    actionSheet.popoverPresentationController?.sourceRect = sender.frame

    let yesAction = UIAlertAction(title: "はい", style: .default)
    let noAction = UIAlertAction(title: "いいえ", style: .cancel)
    actionSheet.addAction(yesAction)
    actionSheet.addAction(noAction)

    present(actionSheet, animated: true)
}

このアクションシートにカスタムViewを追加してかわいいを作っていこうと思います。

補足

iPadでUIAlertController.Style.actionSheetを使用するには位置情報の設定が必要で、位置情報を設定しない場合にはクラッシュしてしまう為、sourceViewsourceRectを設定しています。

// iPadのクラッシュ対応
actionSheet.popoverPresentationController?.sourceView = sender.superview
actionSheet.popoverPresentationController?.sourceRect = sender.frame

詳細については以前記事を書いたので今回は省かせていただきます。

【Swift】iPadでactionSheetを使用するとクラッシュしたので対応した

UIAlertControllerにカスタムViewを追加する

埋め込むカスタムView

SwiftUIのViewでこのようなViewを作成しました。

UIAlertControllerにaddSubViewをする

作成したカスタムViewをUIAlertController.viewaddSubViewを行います。

UIAlertControllertitleにカスタムViewが良い具合に収まるくらいの改行のテキストを渡します。すると、アラートのタイトル欄が縦に長くなるので、addSubViewをした時に中に収まっているように表現することが出来ます。

@IBAction private func showActionSheet(_ sender: UIButton) {

    // 縦方向にスペースを追加し、ActionSheetのタイトルの縦幅を広くする
    let verticalSpaceText = "\n\n\n\n\n\n\n\n\n\n\n\n\n\n"

    let actionSheet = UIAlertController(title: verticalSpaceText,
                                        message: nil,
                                        preferredStyle: .actionSheet)

    // iPadのクラッシュ対応
    actionSheet.popoverPresentationController?.sourceView = sender.superview
    actionSheet.popoverPresentationController?.sourceRect = sender.frame

    let hostingController = UIHostingController(rootView: CuteView())
    actionSheet.addChild(hostingController)
    // actionSheetにカスタムViewを追加
    actionSheet.view.addSubview(hostingController.view)
    hostingController.didMove(toParent: actionSheet)

    guard let actionSheetView = actionSheet.view else { return }

    // レイアウトの調整
    hostingController.view.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([
        hostingController.view.topAnchor.constraint(equalTo: actionSheetView.topAnchor,
                                                    constant: 40),
        hostingController.view.widthAnchor.constraint(equalTo: actionSheetView.widthAnchor),
    ])

    let yesAction = UIAlertAction(title: "はい", style: .default)
    let noAction = UIAlertAction(title: "いいえ", style: .cancel)
    actionSheet.addAction(yesAction)
    actionSheet.addAction(noAction)
    present(actionSheet, animated: true)
}

埋め込みたいViewによって、レイアウトの制約も調整してみてください。

出来たもの

無事にかわいいが作れました。

おわりに

SwiftUIのconfirmationDialogではViewをカスタムすることが出来ず困っていたのですが、UIAlertController.actionSheetを使用してやや力技ですがカスタムすることが出来ました。

UIKit様、この度はお力を借していただきありがとうございました。

是非、皆様のかわいいも作ってみてください。

参考