😽
「UIKit丸出し」で十分な人向けのSwiftUI
- 「UIKit丸出し」で十分な人向けのSwiftUI(iOS)のコンポーネントカタログです
- 基本コード
-
ContentView
が本体 -
ContentView_Previews
はプレビューの表示
-
import SwiftUI
struct ContentView: View {
var body: some View {
Text("Hello, world!")
.padding()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
- プレビューでコンポーネント部分だけ表示する場合はContentView()に
.previewLayout(.sizeThatFits)
を指定する
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView().previewLayout(.sizeThatFits)
}
}
-
Option + Command + Enter
で 右側のCanvas(プレビュー)の Show/Hide が切り替えられる - プレビューは良く壊れてエラーになる、
Option + Command + P
で再描画できる
共通
Viewを複数配置する
- VStack/HStack/ZStack を使って入れ子にする必要がある
VStack
struct ContentView: View {
var body: some View {
VStack {
Text("Hello, world!")
.font(.title)
.fontWeight(.medium)
.foregroundColor(Color.red)
.multilineTextAlignment(.center)
.padding(.all)
Text("Hello, SwiftUI!")
.font(.title)
.fontWeight(.medium)
.foregroundColor(Color.blue)
.multilineTextAlignment(.center)
.padding(.all)
}
}
}
HStack
struct ContentView: View {
var body: some View {
HStack {
Text("Hello, world!")
.font(.title)
.fontWeight(.medium)
.foregroundColor(Color.red)
.multilineTextAlignment(.center)
.padding(.all)
Text("Hello, SwiftUI!")
.font(.title)
.fontWeight(.medium)
.foregroundColor(Color.blue)
.multilineTextAlignment(.center)
.padding(.all)
}
}
}
ZStack
struct ContentView: View {
var body: some View {
ZStack {
Text("Hello, world!")
.font(.title)
.fontWeight(.medium)
.foregroundColor(Color.red)
.multilineTextAlignment(.center)
.padding(.all)
Text("Hello, SwiftUI!")
.font(.title)
.fontWeight(.medium)
.foregroundColor(Color.blue)
.multilineTextAlignment(.center)
.padding(.all)
}
}
}
Text
struct ContentView: View {
var body: some View {
VStack {
Text("Hello, world!")
.font(.title)
.fontWeight(.medium)
.foregroundColor(Color.red)
.multilineTextAlignment(.center)
.padding(.all)
}
}
}
TextField
- 入力可能なテキスト
struct ContentView: View {
@State var text: String = "hello"
var body: some View {
TextField(text, text: $text)
}
}
SecureField
struct ContentView: View {
@State private var username: String = ""
@State private var password: String = ""
var body: some View {
VStack {
TextField(
"User name (email address)",
text: $username)
.autocapitalization(.none)
.disableAutocorrection(true)
.border(Color(UIColor.separator))
.padding()
SecureField(
"Password",
text: $password
) {
print("username: \(username), password: \(password)")
}
.border(Color(UIColor.separator))
.padding()
}
}
}
TextEditor
- 複数行の入力が可能なTextField
- iOS 14.0+
struct ContentView: View {
@State private var fullText: String = "This is some editable text..."
var body: some View {
TextEditor(text: $fullText)
.padding()
}
}
Label
- iOS 14.0+
struct ContentView: View {
var body: some View {
Label(
title: { Text("Camera") },
icon: { Image(systemName: "camera") }
)
}
}
Button
struct ContentView: View {
var body: some View {
VStack {
Button("Button1") {
print("Button1")
}
Button(action: {
print("Button2")
}, label: {
Text("Button2")
.font(.title)
.fontWeight(.bold)
.foregroundColor(Color.green)
})
}
}
}
EditButton
@State private var fruits = [
"Apple",
"Banana",
"Papaya",
"Mango"
]
var body: some View {
NavigationView{
List {
ForEach(
fruits,
id: \.self
) { fruit in
Text(fruit)
}
.onDelete { self.deleteFruit(at :$0) }
.onMove { self.moveFruit(from: $0, to: $1) }
}
.navigationTitle("Fruits")
.toolbar { EditButton() }
}
}
Image
struct ContentView: View {
let image: UIImage = UIImage(systemName: "camera")!
var body: some View {
Image(uiImage: image)
}
}
- UIImageがnilを許容する場合はifを使って以下のような書き方ができる
struct ContentView: View {
@State var image: UIImage?
var body: some View {
if let image = self.image {
Image(uiImage: image)
}
else {
Button("show") {
image = UIImage(systemName: "camera")
}
}
}
}
List
struct ContentView: View {
let values = ["1","2","3","4","5"]
var body: some View {
List {
ForEach(0..<values.count) { index in
Text(values[index])
}
}
}
}
Form
struct ContentView: View {
var body: some View {
Form {
Text("Text1")
Text("Text2")
Text("Text3")
}
}
}
Menu
- ポップアップメニュー
- iOS 14.0+
struct ContentView: View {
var body: some View {
Menu("Actions") {
Button("Duplicate", action: dummy)
Button("Rename", action: dummy)
Button("Delete…", action: dummy)
Menu("Copy") {
Button("Copy", action: dummy)
Button("Copy Formatted", action: dummy)
Button("Copy Library Path", action: dummy)
}
}
}
func dummy() {
}
}
Link
- タップするとブラウザが起動する
- iOS 14.0+
struct ContentView: View {
var body: some View {
Link("SwiftUI",
destination: URL(string: "https://developer.apple.com/documentation/swiftui")!)
}
}
Toggle
struct ContentView: View {
@State private var vibrateOnRing = false
var body: some View {
Toggle(isOn: $vibrateOnRing) {
Text("Vibrate on Ring")
}
.padding()
}
}
Slider
struct ContentView: View {
@State private var speed = 50.0
@State private var isEditing = false
var body: some View {
VStack {
Slider(
value: $speed,
in: 0...100,
onEditingChanged: { editing in
isEditing = editing
}
)
Text("\(speed)")
.foregroundColor(isEditing ? .red : .blue)
}
}
}
Stepper
struct ContentView: View {
var body: some View {
StepperView()
}
}
struct StepperView: View {
@State private var value = 0
let step = 5
let range = 1...50
var body: some View {
VStack {
Text("Current: \(value) in \(range.description)")
Stepper(value: $value,
in: range,
step: step) {
Text("stepping by \(step)")
}
}
.padding(10)
}
}
ColorPicker
- iOS 14.0+
struct ContentView: View {
@State private var bgColor =
Color(.sRGB, red: 0.98, green: 0.9, blue: 0.2)
var body: some View {
VStack {
ColorPicker("Alignment Guides", selection: $bgColor)
.padding()
}
}
}
ProgressView
- iOS 14.0+
struct ContentView: View {
@State private var progress = 0.5
var body: some View {
VStack {
ProgressView(value: progress)
Button("More", action: { progress += 0.05 })
ProgressView {
Text("Now Processing...")
}
}
}
}
TabView
struct ContentView: View {
var body: some View {
TabView {
Text("The First Tab")
.tabItem {
Image(systemName: "1.square.fill")
Text("First")
}
Text("Another Tab")
.tabItem {
Image(systemName: "2.square.fill")
Text("Second")
}
Text("The Last Tab")
.tabItem {
Image(systemName: "3.square.fill")
Text("Third")
}
}
.font(.headline)
}
}
NavigationView
struct ContentView: View {
let values = ["1","2","3","4","5"]
var body: some View {
NavigationView {
List {
ForEach(0..<values.count) { index in
NavigationLink(destination: Text(values[index])) {
Text(values[index])
}
}
}
.navigationTitle("Camera")
.navigationBarItems(trailing: Button(action: {
print("camera")
}, label: {
Image(systemName: "camera")
})
)
}
}
}
Picker
- ドラム(wheel)型、デフォルト
struct ContentView: View {
@State private var selection = 0
let items = ["1", "2", "3"]
var body: some View {
Picker(selection: $selection, label: Text("Picker")) {
ForEach(0 ..< items.count) { num in
Text(self.items[num])
}
}
}
}
- メニュー型、タップするとメニューが表示される
struct ContentView: View {
@State private var selection = 0
let items = ["1", "2", "3"]
var body: some View {
Picker(selection: $selection, label: Text("Picker")) {
ForEach(0 ..< items.count) { num in
Text(self.items[num])
}
}
.pickerStyle(MenuPickerStyle())
}
}
- セグメント型
struct ContentView: View {
@State private var selection = 0
let items = ["1", "2", "3"]
var body: some View {
Picker(selection: $selection, label: Text("Picker")) {
ForEach(0 ..< items.count) { num in
Text(self.items[num])
}
}
.pickerStyle(SegmentedPickerStyle())
}
}
DatePicker
- 日付、時刻の選択
struct ContentView: View {
@State private var date = Date()
var body: some View {
DatePicker(selection: $date, label: { Text("DatePicker") })
}
}
- ホイール(WheelDatePickerStyle)
struct ContentView: View {
@State private var date = Date()
var body: some View {
DatePicker(selection: $date, label: { Text("DatePicker") })
.datePickerStyle(WheelDatePickerStyle())
}
}
- グラフィカル(GraphicalDatePickerStyle)
struct ContentView: View {
@State private var date = Date()
var body: some View {
DatePicker(selection: $date, label: { Text("DatePicker") })
.datePickerStyle(GraphicalDatePickerStyle())
}
}
Alert
struct ContentView: View {
@State var showAlert = false
var body: some View {
Button("Alert") {
showAlert = true
}
.alert(isPresented: $showAlert, content: {
Alert(title: Text("This is alert"))
})
}
}
dismissButton
struct ContentView: View {
@State var showAlert = false
var body: some View {
Button("Alert") {
showAlert = true
}
.alert(isPresented: $showAlert, content: {
Alert(title: Text("title"), message: Text("message"), dismissButton: .default(Text("了解")){
print("default")
})
})
}
}
dismissButton(cancel)
struct ContentView: View {
@State var showAlert = false
var body: some View {
Button("Alert") {
showAlert = true
}
.alert(isPresented: $showAlert, content: {
Alert(title: Text("title"), message: Text("message"), dismissButton: .cancel(Text("キャンセル")){
print("cancel")
})
})
}
}
primaryButton と secondaryButton
struct ContentView: View {
@State var showAlert = false
var body: some View {
Button("Alert") {
showAlert = true
}
.alert(isPresented: $showAlert, content: {
Alert(title: Text("title"), message: Text("message"), primaryButton: .default(Text("button1"), action: {
print("button1")
}), secondaryButton: .default(Text("button2"), action: {
print("button2")
}))
})
}
}
ActionSheet
struct ContentView: View {
@State var showSheet = false
var body: some View {
Button("Sheet") {
showSheet = true
}
.actionSheet(isPresented: $showSheet, content: {
ActionSheet(title: Text("title"), message: Text("message"), buttons: [
.default(Text("button1"), action: {
print("button1")
}),
.default(Text("button2"), action: {
print("button1")
}),
.default(Text("button3"), action: {
print("button1")
}),
.cancel()
])
})
}
}
Stroke
struct ContentView: View {
var body: some View {
Path { path in
path.addRect(CGRect(x: 100, y: 100, width: 200, height: 200))
}
.stroke(Color.red, lineWidth: 2)
}
}
RoundedRectangle
- Image()の左上を起点にアノテーションを描画、オフセットとサイズを指定する
ZStack(alignment: .topLeading)
struct ContentView: View {
var body: some View {
ZStack(alignment: .topLeading) {
Image(systemName: "person.fill")
.resizable()
.scaledToFit()
RoundedRectangle(cornerRadius: 10)
.fill(Color.blue)
.frame(width:200, height: 200)
.offset(x:100, y:100)
.opacity(0.5)
}
}
}
Spacer
- スペースを入れる
struct ContentView: View {
var body: some View {
VStack {
Spacer()
Text("Hello, world!")
.padding()
Spacer()
Text("Hello, swift!")
.padding()
Spacer()
}
}
}
Font
struct ContentView: View {
var body: some View {
VStack {
VStack {
Text(".largeTitle")
.font(.largeTitle)
Text(".title")
.font(.title)
Text(".title2")
.font(.title2)
Text(".title3")
.font(.title3)
Text(".headline")
.font(.headline)
Text(".subheadline")
.font(.subheadline)
Text(".body")
.font(.body)
Text(".callout")
.font(.callout)
Text(".caption")
.font(.caption)
Text(".caption2")
.font(.caption2)
}
VStack {
Text(".footnote")
.font(.footnote)
}
}
}
}
Discussion