[Swift] Alert에 PickerView 넣기

선주·2022년 7월 2일
0

Swift

목록 보기
18/20

class LocationViewController: UIViewController {

    // MARK: - Properties
    let location = ["서울", "인천", "대전", "대구", "광주", "부산", "울산", "세종", "경기도", "강원도", "충청북도", "충청남도", "경상북도", "경상남도", "전라북도", "전라남도", "제주도"]
    let pickerView: UIPickerView = UIPickerView()
    var focusedRow: Int = 0
    var selectedRow: Int = 0
    
    // MARK: - IBActions
    @IBAction func touchUpAreaButton(_ sender: UIButton) {
        let alert = UIAlertController(title: "지역 선택", message: "\n\n\n\n\n\n\n\n", preferredStyle: .alert)
        
        alert.addAction(UIAlertAction(title: "취소", style: .cancel) { _ in
            self.pickerView.selectRow(self.selectedRow, inComponent: 0, animated: true)
        })
        alert.addAction(UIAlertAction(title: "확인", style: .default) { _ in
            self.selectedRow = self.focusedRow
        })
        
        pickerView.frame = CGRect(x: 0, y: 50, width: 270, height: 130)
        pickerView.delegate = self
        pickerView.dataSource = self
        
        alert.view.addSubview(pickerView)
        self.present(alert, animated: true, completion: nil)
    }
}

// MARK: - PickerView
extension LocationViewController: UIPickerViewDelegate, UIPickerViewDataSource {
    
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }
    
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return location.count
    }
    
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return location[row]
    }

    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        focusedRow = row
    }
    
    func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat
    {
        return 30
    }
    
}

전체 소스코드는 위와 같습니다.

다른 코드는 어렵지 않게 이해할 수 있을 텐데, selectedRow 변수와 focusedRow 변수를 따로 쓰는 이유에 대해서는 짚고 넘어가보겠습니다.

didSelectRow 메소드는 피커뷰를 굴릴 때마다 호출됩니다. 슬라이드를 휙 내려서 여러 지역이 후두두둑 지나가면, 그 많은 지역들에 포커스가 맞춰질 때마다 호출되는 것입니다. 따라서 이 메소드 내에서 selectedRow = row로 최종선택된 지역을 저장하게 되면 확인버튼을 누를 때는 문제가 없지만, 취소버튼을 누를 때가 문제입니다.

만약 [전국]이 선택돼있는 상태에서 피커뷰를 굴리다가 [충청북도]에서 멈췄습니다. 그런데 갑자기 [전국]을 더 보고 싶어져서 취소버튼을 눌렀습니다. 그렇게 [전국]을 더 구경하다가, 다른 지역을 보기 위해 얼럿을 띄웠는데 포커스가 [전국]이 아닌 [충청북도]에 가 있습니다. UX적으로 보기 좋은 상황은 아닙니다 😔

이는 UIPickerView가 마지막으로 선택된 row를 갖고 있다가, 다시 피커뷰가 띄워졌을 때 자동으로 그 row가 선택된 상태를 보여주기 때문입니다.

따라서 취소버튼을 누르면 피커뷰를 다시 원래 상태로 돌려주어야 합니다. 코드로 명시적으로 작성해주어야 하는 것이죠. 그래서 focusedRow 변수가 필요합니다! 💡


didSelectRow 메소드가 불릴 때마다, 즉 피커뷰가 굴러갈 때마다 포커스를 얻었던 지역을 focusedRow = row로 저장합니다.

확인 버튼이 눌리면 selectedRow = focusedRow로 선택지역을 업데이트해줍니다.

취소버튼이 눌리면 피커뷰의 포커스를 원래 지역으로 돌려줘야 하기 때문에 pickerView.selectRow(selectedRow, inComponent: 0, animated: true)로 선택지역을 리셋해줍니다.

profile
기록하는 개발자 👀

0개의 댓글