[swift-users] Issues with UITableView*

Jon Shier jon at jonshier.com
Mon Sep 12 17:43:12 CDT 2016


UITableView already has the notion of “selected rows” built in, so I’d suggest starting there.


Jon

> On Sep 12, 2016, at 6:41 PM, Ole Begemann via swift-users <swift-users at swift.org> wrote:
> 
> > Hmm - interesting to know.  Unfortunately, if I do that, then I get
> > NO indication of selection when I click on ANY row.  Perhaps I need
> > to make some other changes to account for the change in how I get the
> > cell?
> 
> You also need to store your cells' selection state someplace outside of the cells themselves. The cells should not be the "source of truth" for the selection state. Otherwise, when you scroll a cell off screen and then scroll it back, it will lose its state.
> 
> So you should store the selection state of each table row somewhere alongside your `locationList` array. Maybe as an array of pairs like this:
> 
>    var locationList: [(location: LocationObject, selected: Bool)] = [
>        (
>            location: LocationObject(name: "name-1", address: "addr-1", phone: "phone-1", latitude: 40.0, longitude: -80.1),
>            selected: false
>        ),
>        (
>            location: LocationObject(name: "name-2", address: "addr-2", phone: "phone-2", latitude: 40.0, longitude: -80.1),
>            selected: false
>        )
>    ]
> 
> There may be better ways to structure your model data, but this should suffice for now.
> 
> Then:
> 
> 1. In `tableView(_:cellForRowAtIndexPath:)`, use the current value of `item.selected` to configure the cell's selection state:
> 
>    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
>        let cell = tableView.dequeueReusableCellWithIdentifier("resultCell", forIndexPath: indexPath) as! ExistingLocationTableViewCell
>        let item = locationList[indexPath.row]
> 
>        cell.nameLabel.text     = item.location.name
>        cell.locationLabel.text = item.location.address
> 
>        cell.accessoryType = item.selected ? .Checkmark : .None
> 
>        return cell
>    }
> 
> One note: on iOS, the convention for table views is that rows should generally not remain selected after the user lifts their finger. Adding the checkmark should be enough to show a cell's selection state. I would only set the checkmark and leave `cell.selected` as is (I left it out in the code above).
> 
> 2. In `didSelectRow...`, toggle the selection state in your model data:
> 
>    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
> 
>        // Update model
>        let row = indexPath.row
>        locationList[row].selected = !locationList[row].selected
> 
> To update the UI, you now have two choices. Either ask the table view for the cell at the index path and modify the cell directly:
> 
>        // Either do this:
>        if let cell = tableView.cellForRowAtIndexPath(indexPath) {
>            cell.accessoryType = locationList[row].selected ? .Checkmark : .None
>        }
> 
> If you do that, I don't think you need to reload the cell explicitly. Alternatively, tell the table view to reload the cell as you are doing now. It will then call `tableView(_:cellForRowAtIndexPath:)` again, which in turn will configure the cell with your model data:
> 
>        // Or this:
>        tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .None)
> 
> Finally, fade out the cell selection:
> 
>        tableView.deselectRowAtIndexPath(indexPath, animated: true)
>    }
> 
> 3. If you are okay with keeping the cells deselected unless the user's finger is onscreen, you don't need to implement `didDeselectRow...` at all.
> 
> (I typed this mostly without help from the compiler as I don't have a Swift 2.x handy, so there may be some errors in the code above.)
> 
> Ole
> _______________________________________________
> swift-users mailing list
> swift-users at swift.org
> https://lists.swift.org/mailman/listinfo/swift-users



More information about the swift-users mailing list