SwiftUIの基礎学習とUIKitとの連携【iOS】
公開日: 2023/5/5
先日SwiftUIに初めて触れてシンプルなコードでUIが実装できることにとても魅力を感じました。
SwiftUIについてもっと詳しく調べたくなったので、基礎的なことを組み合わせてどんな事ができるのかもう少し詳しく調べてみたいと思います。
環境
・MacOS Ventura 13.0
・Xcode 14.2
・Swift version 5.7.2
1. 画像を並べてスクロール可能にする
animal1~animal3画像を作成しました。これらを2列に並べて縦スクルロールしてみます。
1-1. GeometoryReaderの追加
body内にGeometoryReaderを追加します。
GeometoryReaderを使うと親Viewのサイズを取得することが可能になります。
例) geometory.size.width
GeometoryReaderを使うと親Viewのサイズを取得することが可能になります。
例) geometory.size.width
GeometryReader { geometory in
}
1-2. ScrollViewの追加
GeometoryReader内に縦スクルロールのScrollViewを追加します。
ScrollView(.vertical, showsIndicators: false ) {
}
1-3. 画像を並べる
ScrollView内に画像を並べます。
VStackで縦並びにした後ループ内で横並び(2列)に画像を表示しています。
frameのheightの設定は横画面に対応するための処理です。
VStackで縦並びにした後ループ内で横並び(2列)に画像を表示しています。
frameのheightの設定は横画面に対応するための処理です。
VStack {
ForEach(1..<4) { i in
HStack {
Image("animal\(i)").resizable().frame(width: geometory.size.width / 2)
Image("animal\(i)").resizable().frame(width: geometory.size.width / 2)
}.frame(height: UIDevice.current.orientation.isLandscape ? 300 : 150)
}
}
1-4. 完成
レイアウトが完成しました。縦スクルロールもプレビューで確認できます。
2. SwiftUIでUIKitを使う
検索バー(UISearchbar)に文字列を入力して一致するもののみ表示するサンプルを作ってみます。
UIKitをのViewを使うためにはUIViewRepresentableを使用します。
UIKitをのViewを使うためにはUIViewRepresentableを使用します。
2-1. UISearchBarを表示するための構造体を作成する
SearchViewという構造体を追加してUIViewRepresentableを参照します。
makeUIViewとupdateUIViewは必ず必要なので予め追加しておきます。
今回は何も処理はしません。
UIKitのイベント全般を管理するクラスです。
以上で構造体SearchViewは完成しました。
SarchViewとListを使って実際に文字列を検索してみます。
makeUIViewとupdateUIViewは必ず必要なので予め追加しておきます。
makeUIView
makeUIViewではUISearchBarのインスタンスを生成しています。func makeUIView(context: Context) -> UISearchBar {
let searchbar = UISearchBar()
searchbar.barStyle = .default
searchbar.autocapitalizationType = .none
searchbar.delegate = context.coordinator
return searchbar
}
updateUIView
データが更新された際にUIViewにデータを反映させる処理をここに追加します。今回は何も処理はしません。
func updateUIView(_ uiView: UISearchBar, context: Context) {
}
Coordinator
Coordinatorクラスでは検索バーに入力された文字列を受けています。UIKitのイベント全般を管理するクラスです。
@Binding var txt : String
func makeCoordinator() -> Coordinator {
return Coordinator(parent: self)
}
class Coordinator : NSObject,UISearchBarDelegate {
var parent : SearchView!
init(parent: SearchView!) {
self.parent = parent
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
parent.txt = searchText
}
}
以上で構造体SearchViewは完成しました。
SarchViewとListを使って実際に文字列を検索してみます。
2-2. 文字列一致検索と動作確認
レイアウトは以下のようになりました。
ABCDの配列をListに追加して検索をしてみます。
VStackで縦並びのレイアウトにした後にSearchViewとListを配置しています。
SearchViewに入力された文字列と配列内に含まれる文字列の一致検索が問題なく動作しました。
変数部分とbodyのコードは以下になります。
(localizedStandardContainsは大文字と小文字の区別をつけない設定です。)
SwiftUIでUIKitを扱うサンプルが完成しました。
ABCDの配列をListに追加して検索をしてみます。
VStackで縦並びのレイアウトにした後にSearchViewとListを配置しています。
SearchViewに入力された文字列と配列内に含まれる文字列の一致検索が問題なく動作しました。
変数部分とbodyのコードは以下になります。
(localizedStandardContainsは大文字と小文字の区別をつけない設定です。)
@State var datas = ["A", "B", "C","D"]
@State var txt = ""
var body: some View {
VStack {
SearchView(txt: $txt)
List(datas.filter{ txt == "" ? true : $0.localizedStandardContains(txt)},id: \.self){ i in
Text(i).fontWeight(.heavy)
}
}
}
SwiftUIでUIKitを扱うサンプルが完成しました。
3. ContextMenuを使ってみる
ContextMenuはViewを長押ししたとにメニューを表示する機能です。
画像を長押ししたらメニューが表示されるサンプルを作ってみます。
3-1. コードの説明
画面の真ん中に画像を配置しています。
画像のリサイズを可能にして、サイズは縦横どちらも100に指定しています。
アスペクト比が崩れないように.fitを設定しています。
最後に画像に対して.contextMenuを追加することで長押し時にメニューの表示ができるようになります。
Menuの表示内容はVStackで縦並びに指定した後にボタンを2個配置しています。
削除ボタンと保存ボタンとしました。
画像はシステムアイコンを使用しています。
SF SymbolsをApple公式サイトからダウンロードしておくとシステムアイコンを探す時に便利です。
https://developer.apple.com/jp/sf-symbols/
画像のリサイズを可能にして、サイズは縦横どちらも100に指定しています。
アスペクト比が崩れないように.fitを設定しています。
最後に画像に対して.contextMenuを追加することで長押し時にメニューの表示ができるようになります。
Menuの表示内容はVStackで縦並びに指定した後にボタンを2個配置しています。
削除ボタンと保存ボタンとしました。
画像はシステムアイコンを使用しています。
SF SymbolsをApple公式サイトからダウンロードしておくとシステムアイコンを探す時に便利です。
https://developer.apple.com/jp/sf-symbols/
Image("animal1").resizable().frame(width: 100, height: 100).aspectRatio( contentMode: .fit)
.contextMenu {
VStack {
Button {
print("削除")
} label: {
Image(systemName: "trash")
Text("削除")
}
Button {
print("保存")
} label: {
Image(systemName: "folder")
Text("保存")
}
}
}
4. ImagePickerを使ってみる
ImagePickerを使って、写真アプリから選択した写真を画面に表示する機能を作ってみます。
UIViewControllerRepresentableを参照してImagePickerと言う構造体を作ります。
4-1. makeUIViewController
makeUIViewControllerではUIImagePickerControllerのインスタンスを生成しています。
func makeUIViewController(context: Context) -> UIImagePickerController {
let controller = UIImagePickerController()
controller.sourceType = .photoLibrary
controller.delegate = context.coordinator
return controller
}
4-2. updateUIViewController
updateUIViewControllerは今回は何もしません。
コードを書いておかないとエラーになるため追加します。
変数には@Bindingを指定することで変更をViewに反映することができるようになります。
変数は画像のデータ保持用とPickerの表示非表示を管理する変数のみとなります。
コードを書いておかないとエラーになるため追加します。
func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
}
Coordinator
CoordinatorではUIImagePickerControllerのイベントの受け取りと変数へのデータのセットを行っています。変数には@Bindingを指定することで変更をViewに反映することができるようになります。
class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
@Binding var shown : Bool
@Binding var imgData: Data
init(imgData1: Binding, shown1: Binding) {
_imgData = imgData1
_shown = shown1
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
shown.toggle()
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let image = info[.originalImage] as! UIImage
imgData = image.jpegData(compressionQuality: 80)!
shown.toggle()
}
}
@Binding var shown : Bool
@Binding var imgData: Data
func makeCoordinator() -> ImagePicker.Coordinator {
return Coordinator(imgData1: $imgData, shown1: $shown)
}
レイアウトと変数の設定
レイアウトはImageとButtonだけのシンプルなレイアウトにします。変数は画像のデータ保持用とPickerの表示非表示を管理する変数のみとなります。
@State var imageData = Data.init(count: 0)
@State var shown = false
var body: some View {
VStack {
if imageData.count != 0 {
Image(uiImage: UIImage(data: imageData)!).resizable().frame(height: 300).padding().cornerRadius(20)
}
Button("Sheetを開く") {
self.shown.toggle()
}
.sheet(isPresented: $shown) {
Image
5. まとめ
いかがでしたでしょうか。
今回はSwiftUIの基礎を学びながら簡単なアプリを作ってみました。
UIkitとの連携が主な内容となりました。
UIKitとの連携部分はコードの量が増えてしまいますが、一回覚えてしまえばパターンは同じような感じで実装できるので、SwiftUIメインでアプリを作るのも良さそうに感じました。
参考になる部分があれば幸いです。