2021. 5. 24. 17:59ㆍDeveloper.TokkiSea/Apple
1편에 이어서
SwiftUI 스터디 겸
메모 겸 쓰는 글이라서
전문적이지 못하고 설명이 틀린 부분이
있을 수 있습니다.
오늘 첫 번째 전체 소스입니다.
대충 보시고 아래 설명을 먼저 보세요.
import SwiftUI
struct ContentView: View {
@State var phoneNumberString = ""
@State var nameString = ""
@State var age = 0
@State var 선택한동물 = ""
@State var isEditing = false
let 동물 = ["강아지","고양이","토끼"]
init() {
UISegmentedControl.appearance().selectedSegmentTintColor = .blue
UISegmentedControl.appearance().setTitleTextAttributes([.foregroundColor: UIColor.white], for: .selected)
UISegmentedControl.appearance().setTitleTextAttributes([.foregroundColor: UIColor.red], for: .normal)
}
var body: some View {
NavigationView {
Form {
Section(header: Text("Input"), content: {
TextField("name", text: $nameString) { editing in
isEditing = editing
} onCommit: {
}
TextField("phone number", text: $phoneNumberString)
.keyboardType(.numberPad)
Picker("Age", selection: $age) {
ForEach(0..<80)
{
Text("\(String($0)) 살")
}
}
Picker(selection: $선택한동물, label: Text("좋아하는 동물을 선택하세요."), content: {
ForEach(0..<동물.count)
{
Text("\(동물[$0])").tag("\(동물[$0])")
}
})
.pickerStyle(SegmentedPickerStyle())
})
SubView(name:$nameString, phoneNumber: $phoneNumberString, age: $age, 선택한동물: $선택한동물)
}.navigationTitle("Hello TokkiSea")
.gesture(TapGesture().onEnded({
UIApplication.shared.windows.first{$0.isKeyWindow }?.endEditing(true)
}), including: isEditing ? .all : .none)
}
}
}
struct SubView: View {
@Binding var name : String
@Binding var phoneNumber : String
@Binding var age : Int
@Binding var 선택한동물 : String
var body: some View {
Section(header: Text("Output")) {
Text("Name : \(name)\nPhoneNumber : \(phoneNumber)")
Text("Age : \(age)")
Text("선호하는 반려동물 : \(선택한동물)")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
@State var 선택한 동물 = ""
let 동물 = ["강아지", "고양이", "토끼"]
배열은 간단하게 이런 식으로 사용하고요.
TextField에 키보드 타입을 정할 수 있습니다.
TextField("phone number", text: $phoneNumberString)
.keyboardType(.numberPad)
이런 식으로 숫자패드 등 여러 가지가 있어요.
그런데 입력한 후 다른 무슨 행동을 해도 키보드가 내려가지 않을 겁니다.
그래서 조금 다른 방식으로 TextField를 사용해 봅니다.
@State var isEditing = false
TextField("name", text: $nameString) { editing in
isEditing = editing
} onCommit: {}
.keyboardType(.default)
저도 이렇게 쓰는 게 깔끔한 건진 잘 모르겠지만
찾아본 것 중에 가장 깔끔해 보입니다.
먼저 플래그를 하나 만들어주시고
TextField 사용 방식을 OnChanged 방식으로 사용해 봅니다.
아시겠지만 자동으로 완성된 후 Tab을 누르면 수정해야 하는 부분을
하나씩 넘어가게 되고 엔터를 누르면 입력할 수 있겠죠?
StringProtocol 은 그냥 "텍스트" 입력이고
Binding <String>는 얼핏 보면 헛!! 할 수 있지만..;;
이전 편에서 보셨듯이 바인딩해주면 됩니다.
$nameString 이거요.
그다음 onEditingChanged: (Bool) -> Void 도 그냥 엔터 쳐보시면
{ Bool in
...
}
으로 나오고요. Bool 도 엔터 쳐서 사용할 변수명을 정해줍니다.
onCommit도 동일하게요.
이제 완성된 모습은 "OnEditingChanged"라는 표현이 없어요.
그래서 저 Bool 변수에 "onEditingChanged"라고 적어놔도 좋을 것 같네요.
이제 Form의 맨 아래에 붙어 있는
.gesture(TapGesture().onEnded({
UIApplication.shared.windows.first{$0.isKeyWindow }?.endEditing(true)
}), including: isEditing ? .all : .none)
이 코드가 키보드를 내려주는 기능입니다.
그런데 including: 에서 isEditing를 사용하고 있어요.
이렇게 하는 이유는 모든 탭 제스처를 잡아서 키보드 내려주는 기능인데
이렇게 해버리면 탭이 필요한 기능(버튼 등등)이 기능들 모두가 먹통이 돼버립니다.
그래서 "무언가 편집이 되었다" 일 때만. all가 적용되어서
키보드가 내려가게 되지요.
아닐 때는 해당 기능이 먹히도록 해야 합니다.
다음은 픽커입니다.
Picker("Age", selection: $age) {
ForEach(0..<80) {
Text("\(String($0)) 살")
}}
기본 픽커인데 이걸 누르면 아래처럼 선택할 수 있는 리스트가 나옵니다.
ForEach(0..<80) {) 는 0부터 79까지 반복하고
해당 숫자로 0살~79살까지 텍스트를 만들어 줍니다.
리스트에서 선택하게 되면 순수 번호가 나옵니다.
첫 번째는 0, 두 번째는 1...
ForEach(20..<100) {)
을 해도 첫 번째는 0, 두 번째는 1 이예요. 20, 21 이 아니고요.
참고로 ForEach(20..<100) {) 위나 아래에
Text("120살")처럼 따로 추가되는 건 선택이 안됩니다.
(왜 그럴까요;; - 나중에 알게 되겠죠;;)
이번에는 버튼식으로 누를 수 있는 픽커입니다.
Picker(selection: $선택한동물, label: Text("좋아하는 동물을 선택하세요."), content: {
ForEach(0..<동물.count) {
Text("\(동물[$0])").tag("\(동물[$0])")
}})
.pickerStyle(SegmentedPickerStyle())
"동물"은 미리 만들어둔 배열입니다.
let 동물 = ["강아지","고양이","토끼"]
동물.count 는 배열 개수이겠죠?
그렇게 ForEach 내에서는 $0 식의 배열 값을 참조할 수 있습니다.
$0 = 0, 1, 2로 값이 나오고 [0], [1], [2] 식으로 참조하는 거죠.
(이런 내용들은 Swift를 처음 접하시는 분들을 위해 한번 정도만 쓰겠습니다.)
자 이제 픽커 형태를 바꾸는 부분은
.pickerStyle(SegmentedPickerStyle()) 이겁니다.
SegmentedPickerStyle()를 찾아가 보면 다른 종류들의 픽커가 많이 나옵니다.
필요한 걸 찾아서 한번 해보시고, 소스 내부에 설명도 있으니 참조해보세요.
이제 선택을 하면 $선택한동물에 텍스트로 저장됩니다.
label: 은 위의 기본 픽커의 제목으로 사용되는데
지금이건 버튼식이라 제목이 안 나와요.
Section
폼을 구분하고 주제를 보여주는 섹션입니다.
Section(header: Text("Input"), content: {
})
폼이 훨씬 깔끔하게 됩니다.
그리고 버튼 선택 방식 픽커 버튼의 글자 색과 선택 색이 조금 다르게 나오고 있어요.
이건
init() {
UISegmentedControl.appearance().selectedSegmentTintColor = .blue
UISegmentedControl.appearance().setTitleTextAttributes([.foregroundColor: UIColor.white], for: .selected)
UISegmentedControl.appearance().setTitleTextAttributes([.foregroundColor: UIColor.red], for: .normal)
}
이 방식으로 바꿨습니다.
지금은 모든 SegmentedPickerStyle 형태의 색을 다 바꿔버리는데
다음에 개별적으로 바꾸는걸 한번 찾아보겠습니다.
이제 위에 입력된 내용을
SubView(name:$nameString, phoneNumber: $phoneNumberString, age: $age, 선택한동물: $선택한동물)
별도로 만든 뷰로 양방향 바인딩해서 전달하고
OUTPUT 내용을 출력합니다.
TextFiled, Section, Picker, Keyboard dismiss
'Developer.TokkiSea > Apple' 카테고리의 다른 글
RxSwift 정리 1 - Observable 생성 (0) | 2021.08.20 |
---|---|
프로그래머스 - Swift algorithm - BALLOON 단어 찾기 (0) | 2021.08.04 |
SwiftUI 스터디 4. List, GeometryReader, Animation, Selection, SF Symbols (0) | 2021.06.03 |
SwiftUI 스터디 3. StackView, Gradient (0) | 2021.05.27 |
SwiftUI 스터디 1 - Text, Button, From, Navigation, @State, @Binding (0) | 2021.05.12 |