Search code examples
iosiphoneswiftuitableviewuipickerview

How to create a view with two tableviews, each reusing a pickerview on every row


I am developing an app in swift, and one of the pages has two tableviews in it. Each of the table views can have as many rows as the user desires.

Say Table A is about Cats, and Table B is about dogs. The first column of each row in Table A is a pickerview with types of cats, the first column of each row in Table B is a pickerview with types of dogs, and when a user selects from the pickerview, the rest of the cells are populated in that row.

My problem is, I don't know how to get each pickerview to uniquely correspond with the row in the table it's in. I can define the pickers while defining the table rows, but then I don't know how to differentiate between the two tables or define pickerview functionality.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if tableView == dogTable {
      let dogPicker = UIPickerView()
      dogPicker.dataSource = self
      dogPicker.delegate = self
      dogPicker.showsSelectionIndicator = true
      dogPicker.tag = indexPath.row
      cell.dogType.inputView = dogPicker
    } else if tableView == catTable {
      let catPicker = UIPickerView()
      catPicker.dataSource = self
      catPicker.delegate = self
      catPicker.showsSelectionIndicator = true
      catPicker.tag = indexPath.row
      cell.catType.inputView = catPicker
    }
}

func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
   //not sure now how to tell if I'm dealing with Dogs or Cats.

}

I can define a catpickerview and a dogpickerview outside the scope of any function, and therefore differentiate between the two tables, but then I can't set the tag to be specific per row.

lazy var dogPicker : UIPickerView  = { [unowned self] in
    let picker = UIPickerView()
    picker.delegate = self
    picker.dataSource = self
    return picker
}()

lazy var catPicker : UIPickerView  = { [unowned self] in
    let picker = UIPickerView()
    picker.delegate = self
    picker.dataSource = self
    return picker
}()

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if tableView == dogTable {
      dogPicker.tag = indexPath.row 
      // all pickerviews in this table will end up with tag equal to index of final row
      cell.dogType.inputView = dogPicker
    } else if tableView == "catTable" {
      cell.catType.inputView = catPicker
    }
}

func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
    switch pickerView {
        case dogPicker:return Dogs[row].Name
        case catPicker:return Cats[row].Name
        default:return ""
    }
}

So, neither of these methods will work.

How can I accomplish what I need to accomplish? I hope I've provided enough clarification, I can add more if necessary.

EDITED: Changed table comparison to name, not string, as per @Sh_Khan's comment.


Solution

  • The issue here, I think, is that we're bypassing didSelectRowAtIndexPath so the table view never knows it has been selected.

    Can you use didSelectRowAtIndexPath to trigger the picker? This way you can reliably know what tableview and what cell (row) was selected. And in the picker's selection event you can update the underlying data and update the table view with a reload.

    (This depends now what else is going on in your cell.)

    Alternatively, you can inject some additional information into the cell's textfield tag that you can use in a UITextFieldDelegate.