관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swiftUI] TextField, onSubmit, textFieldStyle, @FocusState TextField ViewModifier 개념 본문

iOS 기본 (SwiftUI)

[iOS - swiftUI] TextField, onSubmit, textFieldStyle, @FocusState TextField ViewModifier 개념

jake-kim 2022. 7. 25. 18:17

다른 글) SwiftUI의 기본 - 목차 링크

TextField

  • placeholder와 값을 입력할 수 있는 컴포넌트
  • 사용할땐 @State 프로퍼티를 하나 두고 이 프로퍼티에 바인딩하여 현재 입력값을 상태에 저장
struct ContentView: View {
  @State private var username = ""
  
  var body: some View {
    TextField(
      "User name",
      text: $username
    )
  }
}

TextField 활용

  • 키보드 타입 .keyboardType(_:)
      TextField(
        "User name",
        text: $username
      )
      .keyboardType(.numberPad) // <-
  • onSubmit
    • return 키를 눌렀을때 처리

      TextField(
        "User name",
        text: $username
      )
      .keyboardType(.numberPad)
      .onSubmit { // <-
        print("user did tap return , \(username)")
      }
  • 첫글자를 대문자로 표출 방지
      TextField(
        "User name",
        text: $username
      )
      .keyboardType(.numberPad)
      .onSubmit {
        print("user did tap return , \(username)")
      }
      .textInputAutocapitalization(.never) // <-
  • 자동 수정 기능 비활성화
.disableAutocorrection(true) // <-
  • Rounded 윤곽선
    • .textFieldStyle에.roundedBorder사용 주입

.textFieldStyle(.roundedBorder) // <-

@FocusState

  • iOS 15 부터 가능
  • TextField의 포커스를 코드에서 제어할 수 있는 방법

ex) 유저이름, 이메일 입력 화면이 있을 때, 특정 TextField에 입력을 안한 경우, 해당 TextField로 포커스되도록 설정할때 사용

email 입력 안하고 Sign in버튼을 누를 경우, 포커스가 email 텍스트 필드로 이동

  • Hashable을 따르는 enum타입 정의
  // 아래 타입은 hashable을 따르므로, 따로 Hashable 프로토콜을 선언할 필요 x
  enum Field {
    case username
    case email
  }
  • 텍스트 필드 2개와, @State 두 개 준비
struct ContentView: View {
  @State private var username = ""
  @State private var email = ""
  
  var body: some View {
    VStack {
      TextField(
        "User name",
        text: $username
      )
      
      TextField(
        "Email",
        text: $email
      )
      
      Button("Sign in") {
        if username.isEmpty {
          print("focus to username field")
        } else if email.isEmpty {
          print("focus to email field")
        } else {
          print("Complete Input and sign in...")
        }
      }
    }
  }
}
  • focus 상태를 기록하고 있는 @FocusState를 붙여서 프로퍼티 선언
@FocusState private var focusField: Field?
  • 각 TextField에 바인딩
    • 바인딩의 의미는 양방향을 의미 (한쪽 값이 바뀌면 다른 쪽에 값 전달)
    • .focused(_:equals:)를 사용하여 구현
  var body: some View {
    VStack {
      TextField(
        "User name",
        text: $username
      )
      .focused($focusField, equals: .username) // <-
      
      TextField(
        "Email",
        text: $email
      )
      .focused($focusField, equals: .email) // <-
      
      Button("Sign in") {
      
      ...
  • 버튼이 눌릴때, focusField값을 바꾸면 자동으로 포커스도 이동
      Button("Sign in") {
        if username.isEmpty {
          focusField = .username // <-
        } else if email.isEmpty {
          focusField = .email // <-
        } else {
          print("Complete Input and sign in...") 
        }
      }

키보드 숨기기

  • View에서 self로 손쉽게 쓸 수 있도록 extension 정의
extension View {
  func hideKeyboard() {
    UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
  }
}
  • Button이 눌리고 텍스트 필드가 다 채워져 있는 경우, hideKeybaord() 호출하여 키보드 숨기기 실행
      Button("Sign in") {
        if username.isEmpty {
          focusField = .username
        } else if email.isEmpty {
          focusField = .email
        } else {
          hideKeyboard() // <-
          print("Complete Input and sign in...")
        }
      }
  • 버튼 뿐만이 아닌 빈 곳을 탭해도 키보드가 내려가게 하고싶은 경우
    • VStack의 크기는 내부 contents의 크기만큼 늘어나 있으므로, VStack을 먼저 화면에 꽉차게 정의
VStack {
  ...
}
.frame(maxWidth: .infinity, maxHeight: .infinity) // <-
  • .onTapGesture 를 통해 탭 이벤트 처리
VStack {
  ...
}
.frame(maxWidth: .infinity, maxHeight: .infinity) // <-


* 참고

https://stackoverflow.com/questions/56491386/how-to-hide-keyboard-when-using-swiftui

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

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

Comments