SwiftUI とは
SwiftUIとは、AppleプラットフォームのアプリケーションUIを、開発言語をSwiftとした宣言型シンタックス(Declarative Syntax)で構築するUIフレームワークです。
SwiftUI同様、Apple製品のアプリケーションUIを構築するフレームワークとしてはFlutterが有名ですが、その違いを以下の表にまとめました。
| SwiftUI | Flutter | |
|---|---|---|
| 対応プラットフォーム | Appleのみ | iOS, Android, Web | 
| IDE | Xcode | Android Studio, VS code | 
| 記述形式 | 宣言的シンタックス | 宣言的シンタックス | 
| 開発言語 | Swift | Dart, Widget | 
| コード量 | 少ない | 多い | 
| 拡張性 | Flutterに劣る | 高い | 
Appleプラットフォームのアプリ開発にあたって、Apple公式のフレームワークSwiftUIに注目していきます。
SwiftUI
テキスト
テキスト(Text)
テキスト
Text("<文字列>")
リンク(Link)
リンク
Link(destination: <URL>) { Text("<ラベル>") }
テキストフィールド(Text Field)&セキュアテキストフィールド(Secure Field)
↑テキストフィールド。入力中の状態
テキストフィールドとセキュアテキストフィールド
@State private var value: String = ""
// TextFieldとSecureFieldの値を同一プロパティにすることで連動が可能
TextField("<プレースホルダテキスト>", text: $value)
SecureField("<プレースホルダテキスト>", text: $value)
テキストエディタ
テキストエディタ
@State private var value: String = ""
TextEditor(text: $value)  // テキストエディタはプレースホルダテキストを標準で実装していない
ボタン
システムボタン(Button)
ボタン
Button(action: <実行メソッド>) { <ラベル> }
エディタボタン
エディタボタン
EditButton()
スイッチ(Toggle Button)
スイッチ
@State private var flg: Bool = True
Toggle(isOn: $flg) {
    <ラベル>
}
サインインボタン(Sign In With Apple Button)
サインインボタン
import Authentication Services  // ASAuthorizationAppleIDButtonの実装に必要なパッケージ
struct SignInWithAppleButton: UIViewRepresentable {
    func makeUIView(context: Context) -> ASAuthorizationAppleIDButton {
    // ASAuthorizationAppleIDButtonはApple標準のボタンコンポーネントだが、
    // SwiftUIの標準コンポーネントとして用意されていないため、SwiftUIのViewコンポーネントとして実装する必要がある
        let button = ASAuthorizationAppleIDButton()
        return button
    }
    func updateUIView(_: ASAuthorizationAppleIDButton, context _: Context) [}
}
SignInWithAppleButton()
認証機能を実装したい場合は、[こちら]
(https://inon29.hateblo.jp/entry/2020/03/07/171915)を参照。
ピッカー
ピッカ-(Picker)
ピッカ-
Picker(selection: .<選択値プロパティ名>, label: Text(<ラベル>)) {
    Text(<ラベル>).tag(<選択値>)
}
カラーピッカー(Color Picker)
カラーピッカー
ColorPicker("<ラベル>", selection: .constant(.<既定色>))
日付ピッカー(Date Picker)
日付ピッカー
DatePicker(selection: .constant(Date()), label: { Text("<ラベル>") })
リスト
リスト(List)
リスト
List { <コンテンツ> }
ラベル(Label)
ラベル
Label("<ラベル>", systemImage: "<記号>")
セクション(Section)
セクション
Section(header: Text(<ラベル>)) {
    <コンテンツ>
}
グループ(Disclosure Group)
アウトライン(Outline Group)
アウトライン(実装が難解だったため、ソースコードを記述)
struct CityData: Identifiable {  // OutlineGroupで使用するデータはIdentifiableプロトコルに適合していなければならない
    //構造体"CityData"のプロパティはid, name, sitesの3つ
    let id = UUID()  //UUID(ユニークID)…128bitの16進数
    let name: String
    var sites: [CityData]?  // タイプメソッドresult()によって値が後から代入される
    static func result() -> [CityData] {  // タイプメソッド(静的メソッド)の定義はstaticキーワードを付加
        let city1 = [CityData(name: "Site A"), CityData(name: "Site B")]
        let city2 = [CityData(name: "Site C"), CityData(name: "Site D")]
        return [CityData(name: "city1", sites: city1),
                CityData(name: "city1", sites: city1)]
    }  // タイプメソッドによってsitesの値が以下のようになる
       // [name: city1, sites: Optional([name: site A, sites: nil], [name: Site B, sites: nil]) 
       //  name: city2, sites: Optional([name: site C, sites: nil], [name: Site D, sites: nil])]
}
struct ContentView: View {
    var body: some View {
        List {
            ForEach(CityData.result()) { city in  // CityData.sitesのname: city1, city2のそれぞれに対して以下の処理を実行
                OutlineGroup(city, children: \.sites) { site in  // CityData.sites.sitesのname: site A, site Bのそれぞれに対して以下の処理を実行
                    Text(site.name)
                }
            }
        }
    }
}
Identifiableプロトコル
public protocol Identifiable {
    associatedtype ID: Hashable  //型パラメータ(=プレースホルダ)"ID"は"Hashable"プロトコルに適合
    var id: Self.ID { get }  //プロパティ"id"は読み取り専用であり、インスタンス自身の型パラメータ"ID"に適合
}
Hashableプロトコル
public protocol Hashable{
    func hash(into hasher: inout Hasher)
    var hashValue: Int { get }  
グループボックス(Group Box)
グループボックス
GroupBox(label: <ラベル>) { <コンテンツ> }
グループ
DisclosureGroup("<ラベル>") { <コンテンツ> }
フォーム(Form)
フォーム
Form { <コンテンツ> }
ビュー
ナビゲーションビュー(Navigation View), ナビゲーションリンク(Navigation Link)
ナビゲーションリンク
NavigationView {  //NavigationLinkはNavigationViewのスコープ内で記述
    NavigationLink(destination: <Viewプロトコルに準拠したインスタンス>) { <ラベル> }
}
進捗ビュー(Progress View)
進捗ビュー
ProgressView(value: <0~1の進捗値>)
スクロールビュー(Scroll View)
スクロールビュー
ScrollView(.<方向>) {
    VStack {   // 縦方向の場合はVStackでまとめる
        <コンテンツ>
    }
    .frame(maxWidth: .infinity)  // 対象範囲の最大化
}
スライダ(Slider)&ステッパ(Stepper)
スライダとステッパ
@State private var value: Double = 0
// SliderとStepperの値を同一プロパティにすることで連動が可能
Slider(value: $value, in: 0...100)
Stepper(value: $value, in: 0...100) {
    <ラベル>
}
タブバー(Tab View)
タブバー
@State private var selection = 0 // 選択タブを保持するプロパティ
TabView(selection: $selection) {
    Text("<コンテンツ>").tabItem { Text(<ラベル>) }.tag(0)
    Text("<コンテンツ>").tabItem { Text(<ラベル>) }.tag(1)
}





























