예로 텍스트 뷰에서 코드 상으로 키보드를 올렸다 내릴 수 있습니다

 

값을 초기화하지 않아도 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
ytw_developer