0

I'm having trouble applying a Done button to my pickers.

I've been working through the solution provided in [https://stackoverflow.com/a/52777282/9383241][1] but this only gives an example where there is one picker on a page. I have two pickers in my use case and I distinguish between them using tags, which works for defining the functions within "extension MyViewController: UIPickerViewDataSource, UIPickerViewDelegate" - but I'm unsure how to use the tags in "extension MyViewController: ToolbarPickerViewDelegate {"

I can see that someone has commented saying "It might better for didTapDone and didTapCancel method to pass in the ToolbarPickerView instance; like func didTapDone(_ picker: ToolbarPickerView)" <--- I think that this is what I need, but I don't know how to do it.

Here's my code working for textField1 only, and I've included how I was thinking of structuring my code to implement the didTapDone and didTapCancel for my two pickers in comments.

import UIKit

class MyViewController: UIViewController {

    @IBOutlet weak var textField1: UITextField!
    @IBOutlet weak var textField2: UITextField!
    
    fileprivate let pickerView1 = ToolbarPickerView()
    fileprivate let pickerView2 = ToolbarPickerView()
    fileprivate let titles1 = ["0", "1", "2", "3"]
    fileprivate let titles2 = ["9", "8", "7", "6"]
    
    override func viewDidLoad() {
        super.viewDidLoad()

        self.textField1.inputView = self.pickerView1
        self.textField1.inputAccessoryView = self.pickerView1.toolbar

        self.textField2.inputView = self.pickerView2
        self.textField2.inputAccessoryView = self.pickerView2.toolbar

        self.pickerView1.dataSource = self
        self.pickerView1.delegate = self
        self.pickerView1.toolbarDelegate = self
        self.pickerView1.tag = 1

        self.pickerView1.reloadAllComponents()

        self.pickerView2.dataSource = self
        self.pickerView2.delegate = self
        self.pickerView2.toolbarDelegate = self
        self.pickerView2.tag = 2

        self.pickerView2.reloadAllComponents()
    }
}
extension MyViewController: UIPickerViewDataSource, UIPickerViewDelegate {

    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        switch pickerView.tag {
        case 1:
            return self.titles1.count
        case 2:
            return self.titles2.count
        default:
            return 1
        }
    }

    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }

    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        switch pickerView.tag {
        case 1:
            return self.titles1[row]
        case 2:
            return self.titles2[row]
        default:
            return ""
        }
        
    }

    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        switch pickerView.tag {
        case 1:
            self.textField1.text = self.titles1[row]
        case 2:
            self.textField2.text = self.titles2[row]
        default:
            break
        }

    }
}

extension MyViewController: ToolbarPickerViewDelegate {

    func didTapDone() {
     //   switch pickerView.tag { // <--- I don't know how to get this into the function to be read here
     //   case 1:
            let row = self.pickerView1.selectedRow(inComponent: 0)
            self.pickerView1.selectRow(row, inComponent: 0, animated: false)
            self.textField1.text = self.titles1[row]
            self.textField1.resignFirstResponder()
     /*   case 2:
            let row = self.pickerView2.selectedRow(inComponent: 0)
            self.pickerView2.selectRow(row, inComponent: 0, animated: false)
            self.textField2.text = self.titles2[row]
            self.textField2.resignFirstResponder()
        default:
            break
        }*/

    }

    func didTapCancel() {
    //   switch pickerView.tag { // <--- I don't know how to get this into the function to be read here
    //   case 1:
            self.textField1.text = nil
            self.textField1.resignFirstResponder()
    /*   case 2:
             self.textField2.text = nil
             self.textField2.resignFirstResponder()
       default:
           break
       }*/
    }
}

And a direct copy with no changes of the ToolbarPickerView code:

import Foundation
import UIKit

protocol ToolbarPickerViewDelegate: class {
    func didTapDone()
    func didTapCancel()
}

class ToolbarPickerView: UIPickerView {

    public private(set) var toolbar: UIToolbar?
    public weak var toolbarDelegate: ToolbarPickerViewDelegate?

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.commonInit()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.commonInit()
    }

    private func commonInit() {
        let toolBar = UIToolbar()
        toolBar.barStyle = UIBarStyle.default
        toolBar.isTranslucent = true
        toolBar.tintColor = .black
        toolBar.sizeToFit()

        let doneButton = UIBarButtonItem(title: "Done", style: .plain, target: self, action: #selector(self.doneTapped))
        let spaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
        let cancelButton = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(self.cancelTapped))

        toolBar.setItems([cancelButton, spaceButton, doneButton], animated: false)
        toolBar.isUserInteractionEnabled = true

        self.toolbar = toolBar
    }

    @objc func doneTapped() {
        self.toolbarDelegate?.didTapDone()
    }

    @objc func cancelTapped() {
        self.toolbarDelegate?.didTapCancel()
    }
}
  • 1
    Do you even need to use tags? Can't you use the `===` equality operator to compare the pickerview passed into the method to your two pickerView object ` if pickerView === pickerView1 {...}` – flanker Apr 24 '21 at 15:31

1 Answers1

1

First, add the parameter to the delegate method declarations:

protocol ToolbarPickerViewDelegate: class {
    func didTapDone(pickerView: ToolbarPickerView)
    func didTapCancel(pickerView: ToolbarPickerView)
}

Then, when you call the delegate methods in doneTapped and cancelTapped, you also pass in self:

@objc func doneTapped() {
    self.toolbarDelegate?.didTapDone(pickerView: self)
}

@objc func cancelTapped() {
    self.toolbarDelegate?.didTapCancel(pickerView: self)
}

Now you can check the tag in your VC:

extension MyViewController: ToolbarPickerViewDelegate {

    func didTapDone(pickerView: ToolbarPickerView) {
        switch pickerView.tag {
        case 1:
            let row = self.pickerView1.selectedRow(inComponent: 0)
            self.pickerView1.selectRow(row, inComponent: 0, animated: false)
            self.textField1.text = self.titles1[row]
            self.textField1.resignFirstResponder()
        case 2:
            let row = self.pickerView2.selectedRow(inComponent: 0)
            self.pickerView2.selectRow(row, inComponent: 0, animated: false)
            self.textField2.text = self.titles2[row]
            self.textField2.resignFirstResponder()
        default:
            break
        }

    }

    func didTapCancel(pickerView: ToolbarPickerView) {
       switch pickerView.tag {
       case 1:
            self.textField1.text = nil
            self.textField1.resignFirstResponder()
       case 2:
             self.textField2.text = nil
             self.textField2.resignFirstResponder()
       default:
           break
       }
    }
}
Sweeper
  • 213,210
  • 22
  • 193
  • 313