macOS   SwiftUIプログラミング   フォーム

ホーム

【お知らせ】
SwiftUIで作った macOS Todo アプリ ToDone を100ダウンロードまで無料にしました。マニュアルページは、ToDone サポートページ です。

【本文】
今までは、ビュー(View、UI部品)をレイアウトするのに、VStack や HStack 使ってきました。このように View をレイアウトするものをコンテナ(container)と言います。この章では Form(フォーム)いうコンテナの説明をします。なおコンテナも View の一つです。

このコーナーでは、任意のテキストエディタでコードを記述し、 ターミナルを使ってビルドする方法で作業を進めています。Xcode をお使いの場合は、Xcodeで作業する場合 をご一読ください。

なお、ターミナルを使う場合も、Swift コンパイラや SwiftUI フレームワークなどを Mac にインストールするために Xcode をインストールして、一度起動させなければなりません。インストールが終われば Xcode は終了しても大丈夫です。

また、作成したアプリケーションを App Storeに提出するためのファイルにするには、 Xcode を使わなければならなかったかもしれません。 どこかで Xcode を使わずに作る方法を見たような気もするのですが...

私の開発環境は次のとおりです。

  • MacBook Air 2018年モデル、メモリ8G
  • macOS Monterey 12.4
  • Xcode 13.4.1
  • Swift 5.6.1

Form

View.swift


import SwiftUI

struct ContentView: View {
    @State var name = ""
    @State var author = ""
    @State var review = ""
    
    var body: some View {
        VStack {
            Form {
                Section(header:Text("Books").font(.headline)){
                    TextField("Title", text: $name)
                    TextField("Author", text:  $author)
                    }
                Section(header:Text("Review").font(.headline)) {
                    TextEditor(text: $review)
                }
            }
        }
        .padding(10)
        .frame(minWidth: 300, maxWidth: .infinity, minHeight: 200, maxHeight: .infinity)
    }
}
	


App.swift は、以前は Main.swift というファイル名でした。今後は App.swift というファイル名に統一したいと思います。今回は App.swift に変更はありませんが、一応掲載しておきます。

App.swift


import SwiftUI

@main
struct FooApp: App {
    @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {

    func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
        return true
   }
}
	


アプリケーションの名前を変えるために、Info.plist の CFBundleName を書き換えます。ここでは「Review」という名前にしました。 Xcode で作業している場合は、ここは無視してください。 機会があれば、 また説明します。

Info.plist


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"https://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleExecutable</key>
	<string>foo</string>
	<key>CFBundleIconFile</key>
	<string>icon-macbook.icns</string>
	<key>CFBundleName</key>
	<string>Review</string>
</dict>
</plist>
    


ビルド


swiftc App.swift View.swift -o foo
mv foo Foo.app/Contents/MacOS
    

実行

別案A

View.swift


import SwiftUI

struct ContentView: View {
    @State var name = ""
    @State var pass1 = ""
    @State var pass2 = ""
    @State var match = ""
    
    var body: some View {
        VStack {
            Form {
                Section(header:Text("Account").font(.headline)){
                    TextField("Name", text: $name)
                    SecureField("Password", text:  $pass1)
                    }
                Section(header:Text("Again").font(.headline)) {
                    SecureField("Password",text: $pass2, onCommit:{
                        if name != "" {
                        match = pass1 == pass2 ? "Matched!" : "Mismatched."
                        } else {
                            match = "Enter name."
                        }
                    })
                }
            }
            Text(match)
                .font(.largeTitle)
                .fontWeight(.ultraLight)
                .frame(maxWidth:.infinity, maxHeight: .infinity)
        }
        .padding(10)
        .frame(minWidth: 300, maxWidth: .infinity, minHeight: 200, maxHeight: .infinity)
    }
}
    

App.swift に変更はありません。

別案B

View.swift


import SwiftUI

struct ContentView: View {
    @State var name = ""
    @State var pass = ""
    @State var isShow = false
    
    var body: some View {
        VStack {
            Form {
                Section(header: Text("Account")
                    .font(.headline)) {
                        TextField("Name", text: $name)
                        if isShow {
                            TextField("Password", text:$pass)
                    
                        } else {
                            SecureField("Password", text:$pass)
                        }
                    }
                Section(header:Text("Show").font(.headline)){
                    Toggle(isOn:$isShow, label:{Text("Show password")})
                }
            }
            Spacer()
        }
        .padding(10)
        .frame(minWidth: 300, maxWidth: .infinity, minHeight: 200, maxHeight: .infinity)
    }
}
    

App.swift に変更はありません。




5955 visits
Posted: Jun. 28, 2022
Update: Jun. 29, 2022

ホーム   目次