본문 바로가기
Project/SwiftUI 블록와이드

[SwiftUI Project] TextField FirstResponder 텍스트필드 포커싱 하기

by iOS_woo 2022. 9. 16.

검색 화면이 보여지면 자동으로 텍스트필드가 포커싱됩니다.

 

TextField가 보여지면 자동으로 선택되도록 하는 방법입니다. 

iOS 15 이상 타겟이라면 더 좋은 방법이 있다고 하니 참고해주세요..! 

 

먼저 Cunstom 텍스트 필드를 만들어야 합니다. 

struct FirstResponderTextField: UIViewRepresentable {
    
    class Coordinator: NSObject, UITextFieldDelegate {
        
        @Binding var searchText: String
        var becameFirstResponder = false
        
        init(searchText: Binding<String>) {
            self._searchText = searchText
        }
        
        func textFieldDidChangeSelection(_ textField: UITextField) {
            searchText = textField.text ?? ""
        }
        
        // 리턴키를 누르면 포커스 해제됩니다.
        func textFieldShouldReturn(_ textField: UITextField) -> Bool {
            textField.resignFirstResponder()
            return true
        }
    }
    
    @Binding var searchText: String
    let placeHolder: String
    
    func makeUIView(context: Context) -> some UIView {
        let textField = UITextField()
        textField.delegate = context.coordinator
        textField.placeholder = placeHolder
        return textField
    }
    
    func makeCoordinator() -> Coordinator {
        return Coordinator(searchText: $searchText)
    }
    
    func updateUIView(_ uiView: UIViewType, context: Context) {
        if !context.coordinator.becameFirstResponder {
            uiView.becomeFirstResponder()
            context.coordinator.becameFirstResponder = true
        }
    }
}

 

사용할 때는 이렇게 작성할 수 있습니다. 

FirstResponderTextField(searchText: $searchText, placeHolder: "Search")
            .foregroundColor(Color.white)
            .accentColor(Color.theme.binanceColor)
            .frame(height: 30)

 

완성..!
하지만 저의 경우에는 조금 문제가 발생했는데요.

이번에 검색화면을 NavigationView로 보여주는 것이 아니라 GeometryReader를 사용해서 옆에서 등장시켜서 그런지... 

앱을 첫 실행하면 홈화면에서부터 키보드가 올라오는 문제였습니다. 

 

그렇기 때문에 검색화면을 호출할 때 바뀌는 Bool 값에 따라서 FirstResponder TextField가 나타나도록 설정해주었습니다. 

if !showSearchView {
                normalTextField
            } else {
                firstResponderTextField
            }

 

전체코드 

import SwiftUI

struct SearchBarView: View {
    
    @Binding var searchText: String
    @Binding var showSearchView: Bool
    
    var body: some View {
        HStack(spacing: 0) {
            IconView(iconName: "magnifyingglass")
                .padding(.vertical, -10)
                .padding(.horizontal, -5)
            if !showSearchView {
                normalTextField
            } else {
                firstResponderTextField
            }
        }
        .background(Color.theme.searchBar)
        .cornerRadius(25)
    }
}

extension SearchBarView {
    private var normalTextField: some View {
        TextField("Search", text: $searchText)
            .foregroundColor(Color.white)
            .accentColor(Color.theme.binanceColor)
            .frame(height: 30)
    }
    
    private var firstResponderTextField: some View {
        FirstResponderTextField(searchText: $searchText, placeHolder: "Search")
            .foregroundColor(Color.white)
            .accentColor(Color.theme.binanceColor)
            .frame(height: 30)
            .overlay(
                Image(systemName: "xmark.circle.fill")
                    .padding()
                    .foregroundColor(Color.theme.iconColor)
                    .offset(x: 10)
                    .opacity(searchText.isEmpty ? 0.0 : 0.5)
                    .onTapGesture {
                        searchText = ""
                    }
                , alignment: .trailing
            )
    }
}

struct FirstResponderTextField: UIViewRepresentable {
    
    class Coordinator: NSObject, UITextFieldDelegate {
        
        @Binding var searchText: String
        var becameFirstResponder = false
        
        init(searchText: Binding<String>) {
            self._searchText = searchText
        }
        
        func textFieldDidChangeSelection(_ textField: UITextField) {
            searchText = textField.text ?? ""
        }
        
        // 리턴키를 누르면 포커스 해제됩니다.
        func textFieldShouldReturn(_ textField: UITextField) -> Bool {
            textField.resignFirstResponder()
            return true
        }
    }
    
    @Binding var searchText: String
    let placeHolder: String
    
    func makeUIView(context: Context) -> some UIView {
        let textField = UITextField()
        textField.delegate = context.coordinator
        textField.placeholder = placeHolder
        return textField
    }
    
    func makeCoordinator() -> Coordinator {
        return Coordinator(searchText: $searchText)
    }
    
    func updateUIView(_ uiView: UIViewType, context: Context) {
        if !context.coordinator.becameFirstResponder {
            uiView.becomeFirstResponder()
            context.coordinator.becameFirstResponder = true
        }
    }
}

struct SearchBarView_Previews: PreviewProvider {
    static var previews: some View {
        Group {
            SearchBarView(searchText: .constant(""), showSearchView: .constant(true))
                .preferredColorScheme(.dark)
                .previewLayout(.sizeThatFits)
            SearchBarView(searchText: .constant(""), showSearchView: .constant(true))
                .preferredColorScheme(.light)
                .previewLayout(.sizeThatFits)
        }
    }
}

 

FirstResponder 참고한 블로그: 

 

Swift: TextField 기존 Focus 방식과 새롭게 등장한 FocusState 활용하기

SwiftUI TextField에서 기존에 Focus를 처리하던 방식과, iOS 15부터 추가된 FocusState, onSubmit을 이용해 처리하는 방식을 알아보자.

medium.com

FirstResponder 참고한 유튜브: 

 

댓글