[iOS] UITextField + UIPickerView
👨🏻‍💻iOS 공부/iOS & Swift

[iOS] UITextField + UIPickerView

728x90
반응형

UITextField를 클릭하게 되면 보통 키보드가 올라오면서 텍스트를 입력할 수 있게 된다. 

 

키보드가 올라온다는 것은? 커스텀한 입력값을 받을 수 있다는 것이다. 

하지만 커스텀한 값을 받는 것이 아니라 정해진 값을 받고 싶다면 어떻게 해야할까??

 

드롭다운을 생각할 수도 있지만, 외부 라이브러리가 아닌 UIPickerView를 통해 드롭다운을 구현해보고자 한다. 

 

우선 아래와 같이 UITextField는 만들어져있다고 가정해보자. 

 

한 달에 몇 권이나 읽나요? 이 부분을 커스텀한 값으로 받을 수도 있겠지만 드롭다운 내 값으로만 받아보자. 

 

우선 ViewController 내에 드롭다운으로 선택 가능한 선택지를 만들어줘야 한다. 

 

var readbook = ["0권😑","1 ~ 2권","3 ~ 5권", "6 ~ 10권", "10권 이상"]

 

그리고 UIPickerView 또한 생성해줘야 한다. 

let picker = UIPickerView()

 

자 이제 무엇을 해야할까? UITableView나 UICollectionView를 만들면 항상 하던게 무엇인가?

바로 Delegate와 DataSource 프로토콜을 채택해주는 것이다. 

 

extension SignUpViewController: UIPickerViewDelegate, UIPickerViewDataSource {
	// delegate, datasource 연결 및 picker를 textfied의 inputview로 설정한다
    func configPickerView() {
        picker.delegate = self
        picker.dataSource = self
        readTF.inputView = picker
    }
    // pickerview는 하나만
    public func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }
    // pickerview의 선택지는 데이터의 개수만큼
    public func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return readbook.count
    }
    // pickerview 내 선택지의 값들을 원하는 데이터로 채워준다. 
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return readbook[row]
    }
    // textfield의 텍스트에 pickerview에서 선택한 값을 넣어준다.
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        self.readTF.text = self.readbook[row]
    }
}

여기까지 따라했다면 기본적으로 보여질 데이터를 구성을 하게 된 것이다. 

하지만 중요한 것들을 빠뜨렸다. 

 

데이터 입력을 할지 말지를 결정해주는 "취소", "완료" 버튼을 생성하지 않았다! 

이러한 버튼들은 UIBarButtonItem을 통해 만들 수 있다. 

 

func configToolbar() {
	// toolbar를 만들어준다. 
    let toolBar = UIToolbar()
    toolBar.barStyle = UIBarStyle.default
    toolBar.isTranslucent = true
    toolBar.tintColor = UIColor.white
    toolBar.sizeToFit()
    
    // 만들어줄 버튼 
    // flexibleSpace는 취소~완료 간의 거리를 만들어준다.
    let doneBT = UIBarButtonItem(title: "완료", style: .plain, target: self, action: #selector(self.donePicker))
    let flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
    let cancelBT = UIBarButtonItem(title: "취소", style: .plain, target: self, action: #selector(self.cancelPicker))
    
    // 만든 아이템들을 세팅해주고
    toolBar.setItems([cancelBT,flexibleSpace,doneBT], animated: false)
    toolBar.isUserInteractionEnabled = true
    
    // 악세사리로 추가한다. 
    readTF.inputAccessoryView = toolBar
}

// "완료" 클릭 시 데이터를 textfield에 입력 후 입력창 내리기
@objc func donePicker() {
    let row = self.picker.selectedRow(inComponent: 0)
    self.picker.selectRow(row, inComponent: 0, animated: false)
    self.readTF.text = self.readbook[row]
    self.readTF.resignFirstResponder()
}

// "취소" 클릭 시 textfield의 텍스트 값을 nil로 처리 후 입력창 내리기
@objc func cancelPicker() {
    self.readTF.text = nil
    self.readTF.resignFirstResponder()
}

 

여기까지 구현했다면 아래와 같이 잘 작동하는 것을 확인해볼 수 있다.

 

PickerView와 관련한 extension의 전체코드는 아래와 같다. 

더보기
extension SignUpViewController: UIPickerViewDelegate, UIPickerViewDataSource {
    
    func configPickerView() {
        picker.delegate = self
        picker.dataSource = self
        readTF.inputView = picker
        
        configToolbar()
    }
    
    func configToolbar() {
        let toolBar = UIToolbar()
        toolBar.barStyle = UIBarStyle.default
        toolBar.isTranslucent = true
        toolBar.tintColor = UIColor.white
        toolBar.sizeToFit()
        
        let doneBT = UIBarButtonItem(title: "완료", style: .plain, target: self, action: #selector(self.donePicker))
        let flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
        let cancelBT = UIBarButtonItem(title: "취소", style: .plain, target: self, action: #selector(self.cancelPicker))
        
        toolBar.setItems([cancelBT,flexibleSpace,doneBT], animated: false)
        toolBar.isUserInteractionEnabled = true
        
        readTF.inputAccessoryView = toolBar
    }

    @objc func donePicker() {
        let row = self.picker.selectedRow(inComponent: 0)
        self.picker.selectRow(row, inComponent: 0, animated: false)
        self.readTF.text = self.readbook[row]
        self.readTF.resignFirstResponder()
    }

    @objc func cancelPicker() {
        self.readTF.text = nil
        self.readTF.resignFirstResponder()
    }
    
    public func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }
    
    public func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return readbook.count
    }
    
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return readbook[row]
    }
    
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        self.readTF.text = self.readbook[row]
    }
}

UITextField에 UIPickerView를 적용시켜보았다. 

상황에 맞게 정해진 값을 받는다면 데이터를 범주형으로 관리하기도 좋을 듯 하다. 

막상 커스텀한 값으로 받게 되면, 텍스트를 가공하지 않는 이상 "5권" ,"5", "5권 이상" 등 다양한 값들로 받을 수 있어 추후에 데이터를 보여주기에 어려움이 있을 수 있다. 다만 무조건 UIPickerView가 좋다는 것은 아니니 상황에 맞게 적절하게 사용해주면 되겠다!

 

끄읕

728x90
반응형