아래 사진처럼 UIPickerView의 덩어리를 컬럼 또는 컴포넌트라고 부른다. 그래서 아래의 피커뷰는 컬럼(컴포넌트)이 2개인 피커뷰이다. 피커뷰를 사용하려면 컬럼의 갯수에 상관없이 반드시 UIPickerViewDataSource, UIPickerViewDelegate 라는 프로토콜을 채택해야 한다.
UIPickerViewDataSource에는 피커뷰의 컬럼(컴포넌트)을 몇 개로 할 것인지와 각 컬럼에는 몇 줄이나 필요한지 설정할 수 있도록 도와주는 메소드들이 있다. UIPickerViewDelegate에는 각 컴포넌트가 가지고 있는 줄에 들어갈 컨텐츠(문자열이거나 UIView), 줄의 너비, 높이를 설정할 수 있는 메소드들이 있고 특히 피커뷰에서 스크롤을 돌려서 어떤 한 데이터를 선택하면 그 데이터의 인덱스를 알려주는 메소드도 있다.
이 피커뷰에 사용할 데이터는 아래처럼 생겼다. City 객체가 들어있는 배열을 사용할 것이다.
// CitiesManager.swift
struct CitiesManager {
let cities = [
City(name: "Seoul", tourAttractions: ["Nam Mt", "Gyeongbok-Gung", "Han River"]),
City(name: "New York", tourAttractions: ["Times Square", "Central Park", "MOMA"])
]
}
struct City {
let name: String
let tourAttractions: [String]
}
먼저 UIPickerViewDataSource를 채택한 뷰 컨트롤러는 자기 자신을 피커뷰의 dataSource로 등록해야 한다. CitiesManager는 피커뷰에 보여줄 데이터가 들어있는 구조체이다. 그래서 뷰 컨트롤러가 피커뷰에 표시할 데이터와 UIPickerView 사이의 다리 역할을 한다고 보면 된다.
내 데이터 - 뷰 컨트롤러 - UIPickerView
class ViewController: UIViewController, UIPickerViewDataSource {
@IBOutlet weak var testPickerview: UIPickerView!
@IBOutlet weak var pickerResultLabel: UILabel! // 피커뷰에서 선택된 값을 보여주기 위한 UILabel
var citiesManager = CitiesManager()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
testPickerview.dataSource = self
}
}
UIPickerViewDataSource를 채택한 뷰 컨트롤러에 아래의 두 가지 메소드를 구현한다. 어차피 이 메소드들은 필수이기 때문에 구현하지 않으면 경고 메시지가 나온다.
// 피커뷰에 구현하고 싶은 컴포넌트의 갯수를 리턴하면 된다.
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 2
}
// 각 컴포넌트에 들어갈 행의 갯수를 리턴하면 된다.
// 나는 첫번째 컴포넌트에는 도시 이름들을, 두번째 컴포넌트에는 각 도시의 관광지를 보여줄 것이기 때문에
// 아래처럼 컴포넌트 번호에 따라 행의 갯수가 각각 다르게 리턴되도록 하였다.
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if component == 0 {
return citiesManager.cities.count
} else {
// 0번 컴포넌트에서 선택된 행의 인덱스
let selectedCity = testPickerview.selectedRow(inComponent: 0)
return citiesManager.cities[selectedCity].tourAttractions.count
}
}
그 다음 UIPickerViewDelegate 프로토콜을 채택하고 피커뷰의 delegate에 해당 뷰 컨트롤러를 등록한다.
class ViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate {
@IBOutlet weak var testPickerview: UIPickerView!
@IBOutlet weak var pickerResultLabel: UILabel!
var citiesManager = CitiesManager()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
testPickerview.dataSource = self
testPickerview.delegate = self
}
}
UIPickerViewDelegate의 메소드 중에 아래 2개의 메소드를 구현한다. 메소드 이름은 pickerView로 똑같지만 parameter가 다르다.
// 각 컴포넌트의 행마다 어떤 문자열을 보여줄지에 대한 코드를 작성한다.
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
// 0번째 컴포넌트의 행에는 도시 이름이 나오고,
if component == 0 {
return citiesManager.cities[row].name
} else {
// 나머지 컴포넌트의 행에는 0번째 컴포넌트에서 선택한 도시에 대한
// tourAttractions 배열의 값들이 나온다.
let selectedCity = testPickerview.selectedRow(inComponent: 0)
return citiesManager.cities[selectedCity].tourAttractions[row]
}
}
// 피커뷰의 스크롤을 움직여서 값이 선택되었을 때 호출되는 메소드.
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if component == 0 {
// 특정 컴포넌트의 행을 선택하게 하는 메소드이다.
// 그러므로 아래는 1번째 컴포넌트의 0번째 줄을 선택하게 된다.
testPickerview.selectRow(0, inComponent: 1, animated: false)
}
// 선택한 값을 레이블이 보여주는 부분
let cityIdx = testPickerview.selectedRow(inComponent: 0)
let selectedCity = citiesManager.cities[cityIdx].name
let tourIdx = testPickerview.selectedRow(inComponent: 1)
let selectedTourAttraction = citiesManager.cities[cityIdx].tourAttractions[tourIdx]
pickerResultLabel.text = "\(selectedTourAttraction), \(selectedCity)"
// 16번째 줄과 같이 0번째 컴포넌트에서 변화가 감지되었다는 것은
// 1번째 컴포넌트에 보여주어야 할 데이터가 달라졌다는 것이므로
// reloadComponent 메소드를 사용하여 1번째 컴포넌트를 업데이트 한다.
testPickerview.reloadComponent(1)
}
특히 마지막 줄의 testPickerview.reloadComponent(1)를 하지 않으면 이전 데이터가 그대로 노출된다.
깃허브: https://github.com/lyj-ooz/ex-pickerView
GitHub - lyj-ooz/ex-pickerView: ios pickerView practice
ios pickerView practice. Contribute to lyj-ooz/ex-pickerView development by creating an account on GitHub.
github.com
'swift & iOS > ios & xcode' 카테고리의 다른 글
[xcode] 시뮬레이터 스크린샷 캡쳐하기 (0) | 2022.03.14 |
---|---|
xcode 단축키 (0) | 2022.02.16 |
[ios 개발] xcode에서 code snippet 코드 스니펫 만들기 (0) | 2022.02.08 |
[ios 개발] UITextFieldDelegate의 유용한 메소드 3가지 (0) | 2022.01.31 |
[ios 개발] 키보드 사라지게 하기 (0) | 2022.01.31 |