유저의 입력을 받을 수 있는 텍스트필드에 대해 알아보자.
유저의 입력 순간 순간을 감지하거나, 키보드의 리턴(엔터)버튼을 누르는 등
유저 입력부분에는 정말 다양한 커스터마이징이 가능하기 때문에 우선은 기본 기능을 살펴보자.
추가적으로 이전 시간에 배웠던 개념을 복습하는겸 알럿까지 띄워봤다.
먼저 두 글자 이상 받고 싶은 상황이다.
따라서 두 글자가 입력되기 전까지는 저장 버튼이 붉은색이었다가, 두 글자 이상인 경우 초록색으로 변한다.
(혹은 두 글자가 입력되기 전에는 버튼 자체를 disable 시키는 방법도 있다.)
하지만 조건을 만족하지 못한 경우에 알럿을 띄우는 방식을 사용했다.
색이나 애니메이션 등으로 UX를 이끌어 낼 수도 있지만, 만약 그냥 조건을 만족하기 전 버튼을 disable시킨다면
어 왜 저장이 안되지? 하고 의문을 가지는 사람도 있을 거 같아서.. 알럿이 더 명확하다는 생각이 들었기 때문.
// Created by Toughie on 2023/04/29.
//
import SwiftUI
struct TextFieldPrac: View {
//유저가 입력을 하면 변수에 바로 반영된다.
@State var textFieldText: String = ""
//저장 버튼을 누르면 텍스트를 담을 배열
@State var dataArray: [String] = []
//알럿을 위한 변수
@State var showAlert: Bool = false
var body: some View {
NavigationView {
VStack {
//placeHolder
TextField("이름을 입력해 주세요. (예: 홍길동)", text: $textFieldText)
// .textFieldStyle(.roundedBorder)
.padding()
.background(Color.gray.opacity(0.2).cornerRadius(10))
.foregroundColor(Color.blue)
.font(.headline)
Button {
//입력값의 조건을 확인하고, 만족하면 저장하는 로직
if checkText() {
saveText()
}
} label: {
Text("저장".uppercased())
.padding()
.frame(maxWidth: .infinity)
//삼항 연산자를 활용한 컬러 변화
.background(checkText() ? Color.green.opacity(0.2) : Color.red.opacity(0.2))
.cornerRadius(10)
.foregroundColor(Color.blue)
.font(.headline)
}
//입력값의 조건이 만족되지 않았을 때 버튼 자체를 비활성화 하고 싶은 경우
// .disabled(!checkText())
ForEach(dataArray, id: \.self) { data in
Text(data)
}
Spacer()
}
.padding(.horizontal,10)
.navigationTitle("회원 가입")
//알럿
.alert(isPresented: $showAlert) {
Alert(title: Text("글자수 제한"), message: Text("두 글자 이상 입력해 주세요."), dismissButton: .default(Text("OK")))
}
}
}
private func checkText() -> Bool {
if textFieldText.count >= 2 {
return true
} else {
//for alert
showAlert = true
//저장 버튼을 눌렀을 때 텍스트필드를 빈문자열로 초기화 해주기 위함(지워지게)
textFieldText = ""
return false
}
}
private func saveText() {
dataArray.append(textFieldText)
textFieldText = ""
}
}
엇 근데 시뮬레이터를 돌리다 보니 처음보는 경고문구를 발견했다.
이 경고 메시지는 뷰 업데이트 중에 상태(state)를 수정하면 정의되지 않은 동작이 발생할 수 있다는 것을 나타낸다.
@State 변수를 변경하는 부분인데, 스유의 특징상 뷰의 상태가 변경되면 계속 새로 그리기 때문에 발생하는 에러이다.
뷰를 그리고 있는데 뭐가 도중에 바뀐다거나..
사실 이 부분은 동시성 스유의 뷰 드로잉 체계나, 동시성 프로그래밍을 공부해보면 더욱 와닿을 거 같다.
(공부할 거 추가 ㅎㅎ..)
위의 예시 코드에서 checkText()는 사실 문자열이 조건에 부합하는지 확인하고 참/거짓만 리턴하면 되는데
부가적인 역할도 많이 하고 있다.(@State 변수 변경)
따라서 코드를 간결하게 줄이고, 버튼에 역할을 이임하는 방식으로 코드를 수정했다.
(네이밍 이상한건 봐주세요..ㅋㅋ)
// Created by Toughie on 2023/04/29.
//
import SwiftUI
struct TextFieldPrac: View {
@State var textFieldText: String = ""
@State var dataArray: [String] = []
@State var showAlert: Bool = false
var body: some View {
NavigationView {
VStack {
TextField("이름을 입력해 주세요. (예: 홍길동)", text: $textFieldText)
// .textFieldStyle(.roundedBorder)
.padding()
.background(Color.gray.opacity(0.2).cornerRadius(10))
.foregroundColor(Color.blue)
.font(.headline)
Button {
if checkText() {
saveText()
} else {
//checkText()가 false인 경우 실행하는 코드
failSave()
}
} label: {
Text("저장".uppercased())
.padding()
.frame(maxWidth: .infinity)
.background(checkText() ? Color.green.opacity(0.2) : Color.red.opacity(0.2))
.cornerRadius(10)
.foregroundColor(Color.blue)
.font(.headline)
}
// .disabled(!checkText())
ForEach(dataArray, id: \.self) { data in
Text(data)
}
Spacer()
}
.padding(.horizontal,10)
.navigationTitle("회원 가입")
.alert(isPresented: $showAlert) {
Alert(title: Text("글자수 제한"), message: Text("두 글자 이상 입력해 주세요."), dismissButton: .default(Text("OK")))
}
}
}
//코드 단순화, 역할 명확히
private func checkText() -> Bool {
textFieldText.count >= 2
}
private func saveText() {
dataArray.append(textFieldText)
textFieldText = ""
}
private func failSave() {
textFieldText = ""
showAlert = true
}
}
코드를 수정해서 경고를 싹 없애버렸다!
'SwiftUI > SwiftUI(Basic)' 카테고리의 다른 글
35. [SwiftUI] Toggle() 토글 (0) | 2023.04.30 |
---|---|
34. [SwiftUI] TextEditor, Safe Area에 대한 탐구 (0) | 2023.04.30 |
32. [SwiftUI] .contextMenu() 컨텍스트 메뉴, Label() (0) | 2023.04.29 |
31. [SwiftUI] .actionSheet() 액션시트 (0) | 2023.04.29 |
30. [SwiftUI] .alert() 알럿 (0) | 2023.04.29 |