[iOS] UIPickerView 써보기

2 minute read

[AppJam 회고 - 03] UIPickerView 써보기

앱잼에서 사용자의 출생연도를 입력 받아야 할 때가 있었다. Date Picker로 좀 더 자세한 생년월일을 받을 수도 있었지만 자세하게 받을 필요가 없었기 때문에 출생연도만 받는 걸로 합의를 봤었다.

그래서 Date Picker의 부모 클래스? 라고도 할 수 있는 Picker View를 살짝 커스텀 해서 사용해 보았다.

먼저 Picker View를 하나 생성하여 Text Field의 input view 로 설정한다. 또한 커스텀을 위해서 Picker View의 delegate 와 dataSource 도 지정해주어야 한다.

func createYearPicker(){
        let yearPicker = UIPickerView()
        yearPicker.delegate = self
        yearPicker.dataSource = self
        
        userAgeTxtField.inputView = yearPicker
}

또 편한 입력을 위해 ToolBar도 설정해 주었다.

func createToolBar(){
        let toolBar = UIToolbar()
        toolBar.sizeToFit()
        
        let doneBtn = UIBarButtonItem(title: "Done", style: .plain, target: self, action: #selector(SurveyInfoVC.dismissKeyboard))
        let flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil)
        toolBar.setItems([flexibleSpace,doneBtn], animated: false)
        
        userAgeTxtField.inputAccessoryView = toolBar
    }

done 버튼을 추가하여 액션을 지정해 주고, 오른쪽 끝에 있는게 좀 더 편의성이 있지 않을까 해서 flexibleSpace를 생성해서 toolBar의 아이템으로 설정하였다.

이렇게 지정한 뒤에 Delegate와 DataSource에 Picker View 안에 제공할 선택지와 선택했을 때 이벤트를 지정해주면 끝이다.

DataSource 프로토콜을 먼저 살펴보면

    // returns the number of 'columns' to display.
    @available(iOS 2.0, *)
    func numberOfComponents(in pickerView: UIPickerView) -> Int
    
    // returns the # of rows in each component..
    @available(iOS 2.0, *)
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int

열의 개수, 즉 선택할 속성을 정할 수 있고 각 속성의 행의 개수도 지정할 수 있다. 따라서 출생연도만을 받기 때문에 컴포넌트의 갯수는 1이고 출생 연도 선택지로 미리 만들어 놓은 배열의 count를 리턴하도록 하였다.

extension SurveyInfoVC: UIPickerViewDataSource{
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }
    
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return bornInYearList.count
    }
}

다음은 Delegate 프로토콜이다.

    // returns width of column and height of row for each component. 
    @available(iOS 2.0, *)
    optional func pickerView(_ pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat

    @available(iOS 2.0, *)
    optional func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat

    
    // these methods return either a plain NSString, a NSAttributedString, or a view (e.g UILabel) to display the row for the component.
    // for the view versions, we cache any hidden and thus unused views and pass them back for reuse. 
    // If you return back a different object, the old one will be released. the view will be centered in the row rect  
    @available(iOS 2.0, *)
    optional func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String?

    @available(iOS 6.0, *)
    optional func pickerView(_ pickerView: UIPickerView, attributedTitleForRow row: Int, forComponent component: Int) -> NSAttributedString? // attributed title is favored if both methods are implemented

    @available(iOS 2.0, *)
    optional func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView

    
    @available(iOS 2.0, *)
    optional func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int)

다양한 메소드들 이있는데 대략적으로 소개하자면 각 컴포넌트의 너비를 지정하거나, 행 별로 높이를 지정할 수 있고, 각 행의 들어갈 title 또는 AttributedTitle을 넣을 수 있고, 이미지뷰나 커스텀한 UIView를 넣을 수도 있다고 한다 ..! 마지막으로 선택했을 때의 이벤트를 지정할 수도 있다.

내가 필요한 건 간단한 커스텀이였기 때문에 몇가지만 사용하였다.

extension SurveyInfoVC: UIPickerViewDelegate{
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return "\(bornInYearList[row])"
    }
    
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        selectedYear = "\(bornInYearList[row])"
        
    }
}

먼저 각 행에 들어갈 Title을 설정하였는데 이 전에 설정한 배열로 지정해 주었고, 선택 값을 다른 변수에 저장해 주는 이벤트도 지정해 주었다.

#iOS/AppJam_회고

Tags:

Categories:

Updated: