【iOS】初めてのSwiftUI 【Part2】

【iOS】初めてのSwiftUI 【Part1】が長くなりそうだったので、Part2としてこちらに記録します。

それではSwiftUIで新規プロジェクトを作成済みの状態から始めていきます。

環境

・MacOS Ventura 13.0
・Xcode 14.2
・Swift version 5.7.2

1. Input


1-1. Toggle

ToggleはUIKitではUISwitchと同様のUIパーツです。

@State var isEnable = true
Toggle(isOn: $isEnable) {
            Text("Hello")
        }.padding()

1-10. onChange

onChangeでは変更を検知して変更された値を受け取ることができます。

TextFieldに入力されていた値と入力を変更した値を受け取ってみます。

    @State var text = ""
    var body: some View {
           TextField("入力", text: $text)
            .onChange(of: text) { [text] newValue in
                print("変更前:\(text)、変更後\(newValue)")
            }
    }


1-2. Button

ボタンタップ時の処理とボタンの名称を設定します。

Button {
            print("Clicked")
        } label: {
            Text("Button")
        }

画像のボタンを追加したい場合以下のようになります。

Button {
            print("Clicked")
        } label: {
            Image("shark")
        }

1-3. TextField

TextField(title, text: Binding)のtitleはUIKitのTextFieldで設定できたplaceholderとなります。

文字が入力されていないときにtitleに設定された文字列が薄いグレーで表示されます。

Binding<String>は入力する文字列です。

@State var fullName: String = "Taro"
TextField("名前", text: $fullName).textFieldStyle(.roundedBorder)


パスワード入力時など入力した文字列をマスクして表示したい場合はSecureFieldが便利です。

@State var password: String = ""
SecureField("パスワード", text: $password).textFieldStyle(.roundedBorder)

1-4. Slider

続いてSliderの扱い方について調べてみます。

左端が0、右端を100、初期位置を50としました。

スライダーを動かしている間のイベントが取れるので、isEditingをtrueにして編集中のみ数値を赤色にしています。

 @State private var value = 50.0
 @State private var isEditing = false
    var body: some View {
        VStack {
            Slider(
                value: $value,
                in: 0...100,
                onEditingChanged: { editing in
                    isEditing = editing
                }
            )
            Text("\(value)")
                .foregroundColor(isEditing ? .red : .blue)
        }
    }


1-5. DatePicker

DatePickerでは日付を選択して取得することができます。

ttleにはスクリーンショットテキストが入り、selectionはDateの変数、displayedComponentsには日付だけ、日付と時刻などの設定が可能です。

DatePicker("日付を選択", selection: $date, displayedComponents:  [.hourAndMinute, .date])

日本語フォーマットに対応させるには以下のコードを追加します。

.environment(\.locale, Locale(identifier: "ja_JP"))


1-6. Picker

PickerはUISegmentedControlのような機能です。

複数ある選択肢の中からタップすることで1つを選択することができます。

選択状態を保持する変数と選択肢に表示する文字列の配列を準備して以下のように追加します。

    @State var selected = 0
    var array = ["A", "B", "C"]
    var body: some View {
        Picker("選択肢", selection: $selected) {
            ForEach(0 ..< array.count) {
                index in
                Text(self.array[index])
                    .tag(index)
            }
        }
        .pickerStyle(SegmentedPickerStyle())
    }


1-7. Stepper

UIStepperと同等の機能です。

変数を保持して下限、上限を設定して追加できます。

サンプルコードでは-10から10までカウントアップ、ダウンができるようになっています。

    @State var count:Int = 0
    var body: some View {
        VStack {
            Stepper(value: $count, in: -10...10) {
                Text("Count \(count)")
            }
        }
    }


1-8. タップイベント

シングルタップ、ダブルタップは以下のようにonTapGestureを追加します。

var body: some View {
        VStack {
           Text("シングルタップ")
                .onTapGesture {
                    print("シングルタップを検知")
                }
            Text("ダブルタップ")
                .onTapGesture(count: 2) {
                    print("ダブルタップを検知")
                    
                }
        }
    }

1-9. ジェスチャーイベント

ジェスチャーイベントは.gesture内で受け取ることができます。

タップ

 Text("タップ")
                .gesture(
                    TapGesture()
                        .onEnded({ _ in
                            print("タップ終了")
                        })
                )

ドラッグ

DragGestureで最小の移動距離を設定しています。

minimumDistanceを超えてドラッグが終了するとonEndedが呼ばれます。

Text("ドラッグ")
                .gesture(
                    DragGesture(minimumDistance: 50)
                        .onEnded({ _ in
                            print("ドラッグ終了")
                        })
                )

ロングプレス

LongPressGestureではminimumDurationに指定した時間長押しするとonEndedが呼ばれます。


Text("ロングプレス")
                .gesture(
                    LongPressGesture(minimumDuration: 2)
                        .onEnded({ _ in
                            print("ロングプレス終了")
                        })
                )

2. List

ListはUITableViewに似た機能を持ちます。サンプルとしてText3つを表示してみます。

.listStyleに.plainを指定するとTableViewのデフォルトの表示の見た目になりました。

List {
            Text("A")
            Text("B")
            Text("C")
        }.listStyle(.plain)

2-1. セクションで区切る

セクションで区切って表示したい場合、List内にSectionを追加します。

List→Section→Textの形で作ってみます。

 List {
            Section(header: Text("ヘッダー1")) {
                Text("テキスト1")
            }
            Section(header: Text("ヘッダー2")) {
                Text("テキスト2")
            }
        }.listStyle(.plain)



2-2. NavigationView

NavigationViewはUINavigationControllerに似た機能を持ちます。

Navigationbarにタイトルを設定する。

Navigationbarの中央にタイトルを設定する場合は.inlineを指定する必要がありました。

NavigationView {
            Text("テキスト").navigationTitle("タイトル").navigationBarTitleDisplayMode(.inline)
                    }


2-3. NavigationBarにボタンを追加する

NavigationBarにボタンを追加するには.navigationBarItemsが必要です。

Text("テキスト").navigationTitle("タイトル").navigationBarTitleDisplayMode(.inline)
                .navigationBarItems(trailing: Button("ボタン", action: {
                    //
                }))
                    }

2-4. TabView

TabViewはUITabBarControllerに似た機能を持ちます。

FirstViewとSecondViewと言う名前でSwiftUI用のViewを作成し TabViewで切り替えをしてみます。

タブの名称と画像は.tabitemで追加します。


TabView {
            FirstView()
                .tabItem {
                    Label("First", systemImage: "trash")
                }
            SecondView()
                .tabItem {
                    Label("Second", systemImage: "pencil")
                }
        }


3. Group

Vstack、HStackはViewを10個までしか並べることができませんが、Groupでまとめれば1つのViewとなるため11個以上のViewを追加することができます。

VStack {
                Group {
                    Text("text 1")
                    Text("text 2")
                    Text("text 3")
                    Text("text 4")
                    Text("text 5")
                    Text("text 6")
                    Text("text 7")
                    Text("text 8")
                    Text("text 9")
                    Text("text 10")
                }
                Text("text 11")
            }


4. Alert

ボタンタップにアラートを表示させてみます。

タイトル、メッセージ、アラートの閉じるボタンのタイトルを設定します。

    @State private var alert = false
    
    var body: some View {
        Button("Button") {
           alert = true
        }
        .alert(isPresented: $alert) {
            Alert(
                title: Text("Title"),
                message: Text("message"),
                dismissButton: .default(Text("OK"))
            )
        }
    }


5. Navigation


5-1. NavigationLInk

NavigationLinkで画面遷移をしてみます。

NavigationView内にNavigationLinkを追加しないと動作しないため注意が必要です。

NavigationLinkのdestinationには遷移先、labelには中央に表示されるボタンの名前を追加します。

[Move To First View]ボタンをタップするとFirstViewが表示されました。



6. まとめ

今回はPart1に引き続きSwiftUIの基本的な部分を実装してみました。

とにかくコード量が少なくて公式のドキュメントもわかりやすかったので、SwiftUIについて一通り学んでおく価値は有ると感じました。