ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • @FocusState 사용하기
    SwiftUI 2022. 9. 5. 11:37

    안녕하세요. 그린입니다🍏

    이번 포스팅에서는 @FocusState 라는 프로퍼티 래퍼를 사용해 SwiftUI에서 사용되는 텍스트 필드 등의 포커싱을 컨트롤 하는 학습을 해보겠습니다🙌

     

    @FocusState 사용 하지 않았을 경우

    iOS 15부터 나온 개념이라 이전 OS에서는 TextField를 사용하면서 커서가 위치하는 즉 여기서 말하는 포커싱을 사용하는 기술을 SwiftUI에서는 지원하지 않았습니다.

    그렇기에 우리는 늘 그렇듯 SwiftUI만으로는 아직 제공하지 않거나 구현되지 않는 항목이 있으면 UIKit의 도움을 받아야 했어요.

    이번 경우도 동일합니다.

    UIViewRepresentable를 사용해서 결국 UITextView를 만들어 SwiftUI에서 사용시켜줘야 했어요.

    이 과정에서 UITextFieldDelegate 프로토콜을 채택해 아래 보이는 제공 메서드를 통해 TextField의 포커싱을 해제 시켜주거나 포커싱 시켜주거나를 구현해줄 수 있었습니다.

     

    자 그런데 이렇게 불편하게 쓰고 있는 와중 iOS 15부터는 SwiftUI에서 TextField 포커싱을 위해 오늘 소개할 @FocusState를 제공한다고 해요!

     

    그럼 한번 얼마나 간단해졌고 사용이 쉬울지 바로 알아보시죠🙌

     

    @FocusState 요약 및 선언

    우선 앞서 말했듯 프로퍼티 래퍼입니다.

    프로퍼티 래퍼는 짧게 말하면 프로퍼티 래퍼를 프로퍼티 앞에 붙임으로 해당 프로퍼티가 이미 정의되어 구현된 기능을 가질 수 있도록 해요.

    @FocusState는 애플 공식 문서에서 "씬 내 포커싱 위치가 변경됨에 따라 SwiftUI가 업데이트하는 값을 읽고 쓸 수 있도록 해줌"이라고 설명되어 있습니다.

    위에서 우리가 말하고 필요한 기능의 설명과 동일합니다!

    선언은 아래와 같습니다.

    @frozen @propertyWrapper struct FocusState<Value> where Value : Hashable

    Hashable을 따르는 구조체입니다.

    보시다시피 @frozen 래퍼가 붙어 있어 추후 더이상의 case 추가는 없다는걸 명시해주고 있습니다.

    아..! 위에서도 말했지만 iOS 15 이상에서만 사용할 수 있습니다

     

    @FocusState 소개

    해당 래퍼를 사용해 씬의 포커싱 위치와 엮어 뷰를 사용합니다.

    포커싱이 잡힌 TextField로 진입되면 속성이 래핑된 값이 지정해둔 값과 동일하게 업데이트 합니다.

    반대로 포커싱이 아웃되면 그에 맞게 다시 재설정됩니다.

    focused(_:equals:)
    focused(_:)

    를 사용해 포커싱을 컨트롤 할 수 있습니다.

     

    @FocusState 사용하기

    그럼 위에서 간단한 설명을 봤으니 코드로 한번 감을 잡아보죠!

    아래 코드는 공식 문서의 코드 기반입니다.

    import SwiftUI
    
    struct LoginView: View {
      @State var name: String = ""
      @State var password = ""
      @FocusState var focusField: Field?
      
      var body: some View {
        Form {
          TextField("Name", text: $name)
            .focused($focusField, equals: .name)
            .onSubmit {
              focusField = .password
            }
          TextField("Password", text: $password)
            .focused($focusField, equals: .password)
            .onSubmit {
              checkTextFiled()
            }
          Button("Login") {
            checkTextFiled()
          }
        }
        .onAppear {
          DispatchQueue.main.asyncAfter(deadline: .now() + 0.6) {
            focusField = .name
          }
        }
      }
      
      private func checkTextFiled() {
        if name.isEmpty {
          focusField = .name
        } else if password.isEmpty {
          focusField = .password
        } else {
          focusField = nil
          // 로그인 처리 로직 🙌
        }
      }
    }
    
    enum Field: Hashable {
      case name
      case password
    }

    하나씩 간단히 설명을 해볼께요.

    해당 씬은 로그인을 하는 씬입니다.

    저기서 필요한 State 프로퍼티는 우선 name과 password입니다.

    그리고 포커싱되는것을 체크하고 구동시켜주기 위해 포커싱 필드라는 FocusState 프로퍼티를 만듭니다.

    해당 프로퍼티는 아래에서 정의한 Field라는 열거 타입이며 들어올 case를 정의해둡니다.

    그리고 사용부는 아주 간단히 focused() 메서드를 이용해 해당 focusField 프로퍼티를 가지고 비교해줍니다.

    이제 아주 쉽게 저 focusField의 값을 바꿔주기만 한다면 해당 텍스트 필드 영역으로 포커싱이 되는것입니다😀

    전부 쉬운 코드 구현이지만 중요한게 있습니다.

    해당 씬이 onAppear 시 name 필드 영역으로 첫 포커싱이 잡힐 수 있도록 아래와 같이 그냥 구현해주면 안됩니다.

    .onAppear {
      focusField = .name
    }

    해보시면 아시겠지만 정상적이지 않을거에요.

    디버깅을 해보면 focusField에 nil이 들어가 있을 것이구요.

    이는 SwiftUI의 버그나 이슈인지 몰라도 초기화 되는 시점이 명확히 구동되지 않는것 같습니다.

    즉 onAppear 시 focusState를 변경해도 적용이 되지 않는 간증 레퍼들이 아직까지도 많더라구요ㅠㅠ

    (레이웬더리치 공식 글에서도 위 처럼 타임 인터벌을 줘서 비동기적으로 처리했어요!)

    그래서 만약 이 부분에서 비동기 처리를 하지 않아도 간단히 될 수 있는 방법을 알고 계시면 댓글 부탁드립니다!🙏🏻

    위와 같이 구현하면 아래처럼 우리가 원하는 포커싱을 아주 손쉽게 구현시켜줄 수 있습니다.

     

    마무리

    이제 정말 텍스트 필드 responder에 대해 보다 쉽게 사용할 수 있게 되었네요!

    아직 잔버그들이 조금 있는것 같지만 예전 UIKit을 가져와 쓰는것보다야 훨씬 수월합니다🥳

    위 코드들과 UIKit 방식으로 onAppear 이슈를 처리한것은 아래 깃헙 링크에서 보실 수 있습니다🙋🏻

    https://github.com/GREENOVER/playground/tree/main/FocusState

     

    GitHub - GREENOVER/playground: 학습을 하며 간단한 예제들을 만들어 보는 작고 소중한 놀이터

    학습을 하며 간단한 예제들을 만들어 보는 작고 소중한 놀이터. Contribute to GREENOVER/playground development by creating an account on GitHub.

    github.com

     

    [참고자료]

    https://developer.apple.com/documentation/swiftui/focusstate

     

    Apple Developer Documentation

     

    developer.apple.com

    https://developer.apple.com/documentation/uikit/uitextfielddelegate

     

    Apple Developer Documentation

     

    developer.apple.com

    https://www.raywenderlich.com/31569019-focus-management-in-swiftui-getting-started

     

    Focus Management in SwiftUI: Getting Started

    Learn how to manage focus in SwiftUI by improving the user experience for a checkout form.

    www.raywenderlich.com

Designed by Tistory.