タイトルの無いActionSheetを実装する機会があり、UIKitとSwiftUIでの方法を調べたので記載しておきます。
環境
- Xcode 13.3
- iOS 15.4
タイトルの無いActionSheetを表示する
SwiftUI
SwiftUIのActionSheet
はiOS 13.0~ 16.0までの記載があり、現在非推奨になっております。公式ドキュメント内でconfirmationDialog(_:isPresented:titleVisibility:presenting:actions:message:)
を代わりに使うように記載されております。
confirmationDialog
func confirmationDialog<A, M, T>(_ titleKey: LocalizedStringKey, isPresented: Binding<Bool>, titleVisibility: Visibility = .automatic, presenting data: T?, @ViewBuilder actions: (T) -> A, @ViewBuilder message: (T) -> M) -> some View where A : View, M : View
- titleKey
- ダイアログのタイトル
- isPresented
- Confirmダイアログの表示フラグ
- titleVisibility
- タイトルを表示するかしないか
- data
- 表示するデータ
- actions
- ダイアログのアクション
- message
- タイトルの下に表示するメッセージ
実際に使ってみましよう。
コード
コードの例は下記になります。
import SwiftUI
struct ContentView: View {
@State private var shouldPresentDialog = false
@State private var dialogDetail: DialogDetail? = nil
var body: some View {
Button {
shouldPresentDialog.toggle()
if shouldPresentDialog {
dialogDetail = DialogDetail(name: "選択肢")
}
} label: {
VStack {
HStack {
Image(systemName: "circle.fill")
Image(systemName: "circle.fill")
}
Image(systemName: "nose")
.resizable()
.frame(width: 100, height: 100)
}
}
.confirmationDialog("タイトル無し",
isPresented: $shouldPresentDialog,
titleVisibility: .hidden,
presenting: dialogDetail) { detail in
// ダイアログの選択肢
Button {
print(detail.name)
} label: {
Text(detail.name)
}
// キャンセルボタン
Button("キャンセル", role: .cancel) {
dialogDetail = nil
}
}
}
}
struct DialogDetail: Identifiable {
var id: String { name }
let name: String
}
confirmDialog
のtitleKey
にはタイトル無し
と入力していますが、タイトルはtitleVisibility
を.hidden
にすることで非表示に出来ます。
isPresented
で表示非表示を切り替えるフラグを監視おり、ダイアログを閉じるとフラグはfalse
に切り替わります。
presenting
にはダイアログを表示する為のデータを渡して、actions
の中でダイアログのアクションを設定します。
message
はタイトル下に表示されるメッセージですが、こちらは省略可能になります。今回はタイトルの無いダイアログを作成したかった為、こちらは使用しません。
プレビュー
タイトルの無いダイアログが表示出来ました。
UIKit
UIKitでアクションシートを表現する為にUIAlertController
を使用します。
UIAlertController
init(title: String?, message: String?, preferredStyle: UIAlertController.Style)
UIAlertController
の引数のtitle
とmessage
はオプショナル型になっており、引数にnil
を渡すとタイトルの無いUIAlertController
を表示することが出来ます。
また、preferredStyle
を.actionSheet
にすることでアクションシートを表現出来ます。
ただ.actionSheet
にはやや罠があり、通常のアラート実装だけではiPadで使用する時にクラッシュしてしまうので注意が必要です。以前、そのことを記事にしたので今回はその説明は割愛させていただきます。
コード
import UIKit
class ViewController: UIViewController {
@IBAction func showActionSheet(_ sender: UIButton) {
let actionSheet = UIAlertController(title: nil,
message: nil,
preferredStyle: .actionSheet)
// iPadの対応でポップオーバーに対してロケーション情報を渡してあげる必要がある
actionSheet.popoverPresentationController?.sourceView = sender.superview
actionSheet.popoverPresentationController?.sourceRect = sender.frame
let choiceAction = UIAlertAction(title: "選択肢", style: .default) { _ in
print("選択肢")
}
let cancelAction = UIAlertAction(title: "キャンセル", style: .cancel)
actionSheet.addAction(choiceAction)
actionSheet.addAction(cancelAction)
present(actionSheet, animated: true)
}
}
タイトルとメッセージをnil
したアクションシートスタイルのアラートを作成し、各アラートアクションを追加した後にpresent
しています。
プレビュー
タイトルの無いアクションシートが表示出来ました。
おわりに
UIAlertController
はタイトルをnil
ではなく、""
のように空文字にした時の見え方も違うので、色々試行錯誤しながら遊んでみるのも楽しいですね!
また、confirmationDialog
には今回紹介している方法以外でも別の引数を持った呼び出し方法もあるので色々と試してみるもいいかもしれません。