관리 메뉴

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

[iOS - swift] customView, 커스텀뷰에서 becomeFirstResponder(), resignFirstResponder() 처리 방법 (UITextField, UITextView, 키보드) 본문

iOS 응용 (swift)

[iOS - swift] customView, 커스텀뷰에서 becomeFirstResponder(), resignFirstResponder() 처리 방법 (UITextField, UITextView, 키보드)

jake-kim 2022. 1. 26. 03:12

뷰를 터치해도 키보드 등장

커스텀 뷰에서 뷰를 터치해도 키보드가 올라게 하는 방법

  • 커스텀 뷰 터치 이벤트 바인딩에서 UITextField에 접근하여 becomeFirstResponder()를 호출해줄 수 있지만 커스텀 뷰를 사용할땐 UI요소가 private이 되어야 응집도가 높아지므로 다른 방법 사용
  • CustomView에서 becomeFirstResponder(), resignFirstResponder()를 재정의하여 사용
// MyCustomView.swift

@discardableResult
override func becomeFirstResponder() -> Bool {
  super.becomeFirstResponder()
  return self.textField.becomeFirstResponder()
}

@discardableResult
override func resignFirstResponder() -> Bool {
  super.resignFirstResponder()
  return self.textField.resignFirstResponder()
}

예시)

UI를 간편하게 만들기 위해 사용한 프레임워크

  • (코드로 UI 작성)
pod 'RxSwift'
pod 'RxCocoa'
pod 'RxGesture'
pod 'SnapKit'
pod 'Then'

커스텀 뷰 정의

  • 뷰 정의
    //  MyCustomView.swift
    
    import UIKit
    import SnapKit
    import Then
    
    final class MyCustomView: UIView {
      private let titleLabel = UILabel().then {
        $0.textColor = .black
        $0.text = "<인풋 커스텀 뷰>"
        $0.font = .systemFont(ofSize: 32)
        $0.textAlignment = .center
      }
      private let inputInformationLabel = UILabel().then {
        $0.textColor = .black
        $0.text = "입력:"
      }
      private let textField = UITextField().then {
        $0.textColor = .black
        $0.borderStyle = .roundedRect
      }
      
      override init(frame: CGRect) {
        super.init(frame: .zero)
        
        self.layer.borderWidth = 1
        self.layer.borderColor = UIColor.gray.cgColor
        self.layer.cornerRadius = 10
        
        [self.titleLabel, self.inputInformationLabel, self.textField]
          .forEach(self.addSubview(_:))
        
        self.titleLabel.snp.makeConstraints {
          $0.top.equalToSuperview()
          $0.centerX.equalToSuperview()
        }
        self.inputInformationLabel.snp.makeConstraints {
          $0.top.equalTo(self.titleLabel.snp.bottom).offset(4)
          $0.left.equalToSuperview().offset(16)
        }
        self.textField.snp.makeConstraints {
          $0.top.equalTo(self.titleLabel.snp.bottom)
          $0.left.equalTo(self.inputInformationLabel.snp.right).offset(8)
          $0.bottom.equalToSuperview()
          $0.width.equalTo(140)
        }
      }
      
      private var contentSize: CGSize? = nil
      override var intrinsicContentSize: CGSize {
        self.contentSize ?? super.intrinsicContentSize
      }
      
      @available(*, unavailable)
      required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
      }
    }
  • 위 뷰를 터치 했을 때 firstResponder는 textField가 되어야 하므로 overriding 추가
      //  MyCustomView.swift
      
      @discardableResult
      override func becomeFirstResponder() -> Bool {
        super.becomeFirstResponder()
        return self.textField.becomeFirstResponder()
      }
    
      @discardableResult
      override func resignFirstResponder() -> Bool {
        super.resignFirstResponder()
        return self.textField.resignFirstResponder()
      }​

사용하는 쪽

  • textView.becomeFirstResponder()에 직접 접근하지 않아도 뷰만 탭해도 textField.resignFirstResponder()가 동작
//  ViewController.swift

import UIKit
import SnapKit
import RxSwift
import RxCocoa
import RxGesture

class ViewController: UIViewController {
  
  private let myCustomView = MyCustomView()
  private let disposeBag = DisposeBag()

  override func viewDidLoad() {
    super.viewDidLoad()
    self.view.addSubview(self.myCustomView)
    self.myCustomView.snp.makeConstraints {
      $0.top.left.right.equalTo(self.view.safeAreaLayoutGuide).inset(32)
    }
    
    self.myCustomView.rx.tapGesture()
      .map { _ in Void() }
      .bind { [weak self] in self?.myCustomView.becomeFirstResponder() }
      .disposed(by: self.disposeBag)
  }
  
  override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    super.touchesBegan(touches, with: event)
    self.view.endEditing(true)
  }
}

* 전체 코드: https://github.com/JK0369/ExCustomView

 

Comments