예로 텍스트 뷰에서 코드 상으로 키보드를 올렸다 내릴 수 있습니다
값을 초기화하지 않아도 TextField에 의해 자동으로 @FocusState의 값이 정해집니다.
만약 TextField 를 클릭하게 된다면 .focused를 사용하여 인식되어 해당 값이 true로 바뀌게 됩니다.
@FocusState private var usernameInFocus: Bool
@State private var username: String = ""
var body: some View {
VStack {
TextField("Add your name here...", text: $username)
.focused($usernameInFocus)
.frame(height: 55)
.frame(maxWidth: .infinity)
.background(Color.gray.brightness(0.3))
.clipShape(RoundedRectangle(cornerRadius: 10))
}
.padding(40)
}
만약 Button을 만들어 @FocusState의 값을 변경하는 코드를 작성하게 된다면 버튼을 클릭하였을 때 해당 @FocusState 프로퍼티를 focused 인자로 받는 TextField의 키보드를 올리며 입력 상태로 만듭니다.
@FocusState private var usernameInFocus: Bool
@State private var username: String = ""
var body: some View {
VStack {
TextField("Add your name here...", text: $username)
.focused($usernameInFocus)
.frame(height: 55)
.frame(maxWidth: .infinity)
.background(Color.gray.brightness(0.3))
.clipShape(RoundedRectangle(cornerRadius: 10))
Button("TOGGLE FOCUS STATE") {
usernameInFocus.toggle()
}
}
.padding(40)
}
onAppear로 뷰와 함께 키보드 올리기
onAppear를 사용하여 뷰가 나타나자마자 @FocusState의 값을 바꾸게 하려면 다음과 같이 코드를 작성할 수 있습니다.
이때 onAppear에서 DispatchQueue 를 사용하는 이유는 onAppear는 뷰가 랜더링 되기 전에 작업이 수행되기 때문에 랜더링 된 이후에 작업을 수행하도록 하기 위해서 0.5초의 텀을 둔 것입니다.
struct ContentView: View {
@FocusState private var usernameInFocus: Bool
@State private var username: String = ""
var body: some View {
VStack {
TextField("Add your name here...", text: $username)
.focused($usernameInFocus)
.frame(height: 55)
.frame(maxWidth: .infinity)
.background(Color.gray.brightness(0.3))
.clipShape(RoundedRectangle(cornerRadius: 10))
Button("TOGGLE FOCUS STATE") {
usernameInFocus.toggle()
}
}
.padding(40)
.onAppear(perform: {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.usernameInFocus = true
}
})
}
}
간단한 회원가입 구현하기
다음 코드의 설명은 간단합니다. 회원가입을 하기 위한 버튼을 눌렀을 때 username, password 가 모두 비어 있을 경우 username에 focus하여 값을 입력받도록 하며 반대일 경우 password에 focus를 합니다. 만일 둘다 값이 존재하면 버튼의 텍스트를 'SIGN IN SUCCESS' 로 변경합니다.
import SwiftUI
struct ContentView: View {
@FocusState private var usernameInFocus: Bool
@State private var username: String = ""
@FocusState private var passwordInFocus: Bool
@State private var password: String = ""
@State private var buttonText: String = "SIGN UP 🚀"
var body: some View {
VStack {
TextField("Add your name here...", text: $username)
.focused($usernameInFocus)
.frame(height: 55)
.frame(maxWidth: .infinity)
.background(Color.gray.brightness(0.3))
.clipShape(RoundedRectangle(cornerRadius: 10))
TextField("Add your password here...", text: $password)
.focused($passwordInFocus)
.frame(height: 55)
.frame(maxWidth: .infinity)
.background(Color.gray.brightness(0.3))
.clipShape(RoundedRectangle(cornerRadius: 10))
Button(buttonText) {
let usernameIsValid = !username.isEmpty
let passwordIsValid = !password.isEmpty
if usernameIsValid && passwordIsValid {
buttonText = "SIGN IN SUCCESS"
} else if usernameIsValid {
usernameInFocus = false
passwordInFocus = true
} else {
usernameInFocus = true
passwordInFocus = false
}
}
}
.padding(40)
.onAppear(perform: {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.usernameInFocus = true
}
})
}
}
enum과 focused의 equals 사용하기
다음 코드는 enum에서 username 과 password를 구현한 후 focused의 equals에 값을 넣어 해당 값으로 TextField 가 focus가 될 수 있도록 합니다. 이렇게 구현하면 조금 더 간결한 코드를 만들 수 있습니다.
import SwiftUI
struct ContentView: View {
enum OnboardingFields: Hashable {
case username
case password
}
@State private var username: String = ""
@State private var password: String = ""
@State private var buttonText: String = "SIGN UP 🚀"
@FocusState private var fieldInFocus: OnboardingFields?
var body: some View {
VStack {
TextField("Add your name here...", text: $username)
.focused($fieldInFocus, equals: .username)
.frame(height: 55)
.frame(maxWidth: .infinity)
.background(Color.gray.brightness(0.3))
.clipShape(RoundedRectangle(cornerRadius: 10))
SecureField("Add your password here...", text: $password)
.focused($fieldInFocus, equals: .password)
.frame(height: 55)
.frame(maxWidth: .infinity)
.background(Color.gray.brightness(0.3))
.clipShape(RoundedRectangle(cornerRadius: 10))
Button(buttonText) {
let usernameIsValid = !username.isEmpty
let passwordIsValid = !password.isEmpty
if usernameIsValid && passwordIsValid {
buttonText = "SIGN IN SUCCESS"
} else if usernameIsValid {
fieldInFocus = .password
} else {
fieldInFocus = .username
}
}
}
.padding(40)
}
}
전체 코드
import SwiftUI
struct ContentView: View {
enum OnboardingFields: Hashable {
case username
case password
}
// @FocusState private var usernameInFocus: Bool
@State private var username: String = ""
// @FocusState private var passwordInFocus: Bool
@State private var password: String = ""
@State private var buttonText: String = "SIGN UP 🚀"
@FocusState private var fieldInFocus: OnboardingFields?
var body: some View {
VStack {
TextField("Add your name here...", text: $username)
.focused($fieldInFocus, equals: .username)
.frame(height: 55)
.frame(maxWidth: .infinity)
.background(Color.gray.brightness(0.3))
.clipShape(RoundedRectangle(cornerRadius: 10))
SecureField("Add your password here...", text: $password)
.focused($fieldInFocus, equals: .password)
.frame(height: 55)
.frame(maxWidth: .infinity)
.background(Color.gray.brightness(0.3))
.clipShape(RoundedRectangle(cornerRadius: 10))
Button(buttonText) {
let usernameIsValid = !username.isEmpty
let passwordIsValid = !password.isEmpty
if usernameIsValid && passwordIsValid {
buttonText = "SIGN IN SUCCESS"
} else if usernameIsValid {
fieldInFocus = .password
// usernameInFocus = false
// passwordInFocus = true
} else {
fieldInFocus = .username
// usernameInFocus = true
// passwordInFocus = false
}
}
}
.padding(40)
// .onAppear(perform: {
// DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
// self.usernameInFocus = true
// }
// })
}
}
'SwiftUI' 카테고리의 다른 글
버튼 커스텀화하기, Custom ButtonStyle (0) | 2024.04.07 |
---|---|
Custom ViewModifiers (0) | 2024.04.07 |
swipeActions (0) | 2024.04.06 |
.sheet(), .transition(), .animation (0) | 2024.04.06 |
더 적은 데이터로 더 많은 작업하기 (0) | 2024.04.06 |