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)
}