ios - 如何切换 UITableViewContoller/UITableViewCell 中的选定行

标签 ios swift ios9

代码方面发生了很多变化,因为我在过去一周左右一直在尝试对其进行调试 - 因此,我已将原始帖子移至 PDF。并且开始大部分新鲜:

简短概要:(基本未变)

  • 一个 UITableViewController(带有自定义类)包含 UITableViewCell(也是自定义类)
  • 表定义为只允许单选
  • 初始“空”单元格(行 = 0)设置以在顶部提供一些填充 观点
  • 希望能够切换单元格的选择(点击一次, 选中;再次点击它,取消选中)
  • 我的代码(对我来说)看起来应该可以工作,但没有
  • 因此,寻求一些指导/帮助等。

代码

下面是 [相关部分] 自定义 UITableViewController 代码(稍微重新格式化)

import UIKit

class ExistingLocationsViewController: UITableViewController {
    var oldRow = -9999
    var newRow = -1
    var locationList: [LocationObject] = [
        LocationObject(name: "name-1", address: "addr-1", phone: "phone-1", latitude: 40.0, longitude: -80.1),
        LocationObject(name: "name-2", address: "addr=2", phone: "phone-2", latitude: 40.0, longitude: -80.1)
    ]

    override func viewDidLoad() {
        super.viewDidLoad()
        // provides buffer space at the top so that the contents do not run into the top-margin (not needed if first cell is [intnetionally] blank)
        self.tableView.contentInset = UIEdgeInsets(top: 20, left: 0, bottom: 0, right: 0)
    }

    //... didReceiveMemoryWarning, numberOfSectionsInTableView, tableView(tableView: UITableView, numberOfRowsInSection section: Int)
    // Did an override of willDisplayCell, but it seemed to neither hurt nor help my issue, so I removed it

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("resultCell", forIndexPath: indexPath) as! ExistingLocationTableViewCell
        let row  = indexPath.row
        let item = locationList[row]

        cell.nameLabel.text     = item.name
        cell.locationLabel.text = item.address

        print("cellForRowAtIndexPath: (row = \(row))(oldRow = \(oldRow))(newRow = \(newRow))[cell.selected = \(cell.selected)]")
        //...attempt to set cell.accessoryType here neither hurt nor helped my issue, so I removed them

        return cell
    }

    override func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
        let cell = tableView.dequeueReusableCellWithIdentifier("resultCell", forIndexPath: indexPath) as! ExistingLocationTableViewCell
        print("didDeselectRowAtIndexPath: (row = \(indexPath.row))(oldRow = \(oldRow))(newRow = \(newRow))[cell.selected = \(cell.selected)]")
        print("didDeselectRowAtIndexPath => reloadRowsAtIndexPaths")
        self.tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .None)
    }

    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        let cell = tableView.dequeueReusableCellWithIdentifier("resultCell", forIndexPath: indexPath) as! ExistingLocationTableViewCell
        newRow = indexPath.row
        print("didSelectRowAtIndexPath: (row = \(indexPath.row))(oldRow = \(oldRow))(newRow = \(newRow))[cell.selected = \(cell.selected)]")
        if newRow == oldRow  {
            print("didSelectRowAtIndexPath => didDeselectRowAtIndexPath")
            self.tableView(tableView, didDeselectRowAtIndexPath: indexPath)
            cell.setSelected(false, animated: false) // before or after call to didDeselect but must be *here* and not *there*
            oldRow = -1
        }
        else {
            print("didSelectRowAtIndexPath => reloadRowsAtIndexPaths")
            self.tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .None)
            cell.setSelected(true, animated: false) // must be *after* call to reloadRowsAtIndexPaths
            oldRow = indexPath.row
        }
        print("didSelectRowAtIndexPath: oldRow = '\(oldRow)'")
    }

    //... canEditRowAtIndexPath,  commitEditingStyle
}

下面是自定义的UITableViewCell代码(...)

import UIKit

class ExistingLocationTableViewCell: UITableViewCell {
    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var locationLabel: UILabel!

    override func awakeFromNib() { super.awakeFromNib() }

    // This is where the checkmark happens
    override func setSelected(selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
        let nm = self.nameLabel.text
        let ad = self.locationLabel.text
        if (nm?.isEmpty == false) { //avoids many calls to this function which don't represent an actual row
            print("setSelected(\(selected), \(animated)): [name='\(nm)', location='\(ad)']:")
            self.accessoryType = (selected == true) ? .Checkmark : .None
        }
    }

}

记录

下面是日志输出和我所看到的图像(还有一些额外的评论)

(1) 初始显示

    cellForRowAtIndexPath: (row = 0)(oldRow = -9999)(newRow = -1)[cell.selected = false]
    setSelected(false, false): [name='Optional("name-1")', location='Optional("addr-1")']:
    cellForRowAtIndexPath: (row = 1)(oldRow = -9999)(newRow = -1)[cell.selected = false]
    setSelected(false, false): [name='Optional("name-2")', location='Optional("addr-2")']:
    Initial Display
    (好:没有检查或突出显示)


(2) 单击 1:打开
    setSelected(true, false): [name='Optional("name-1")', location='Optional("addr-1")']:
    didSelectRowAtIndexPath: (row = 0)(oldRow = -9999)(newRow = 0)[cell.selected = true]
    didSelectRowAtIndexPath => reloadRowsAtIndexPaths 
    cellForRowAtIndexPath: (row = 0)(oldRow = -9999)(newRow = 0)[cell.selected = false]
    setSelected(false, false): [name='Optional("name-1")', location='Optional("addr-1")']:
    setSelected(true, false): [name='Optional("name-1")', location='Optional("addr-1")']:
    didSelectRowAtIndexPath: oldRow = '0' 
    Initial click
    (好:第 1 行已选中并突出显示)


(3) 单击 2:关闭
    setSelected(true, false): [name='Optional("name-1")', location='Optional("addr-1")']:
    setSelected(false, false): [name='Optional("name-1")', location='Optional("addr-1")']:
    setSelected(true, false): [name='Optional("name-1")', location='Optional("addr-1")']:
    didSelectRowAtIndexPath: (row = 0)(oldRow = 0)(newRow = 0)[cell.selected = true]
    didSelectRowAtIndexPath => didDeselectRowAtIndexPath 
    didDeselectRowAtIndexPath: (row = 0)(oldRow = 0)(newRow = 0)[cell.selected = true]
    didDeselectRowAtIndexPath => reloadRowsAtIndexPaths 
    cellForRowAtIndexPath: (row = 0)(oldRow = 0)(newRow = 0)[cell.selected = false]
    setSelected(false, false): [name='Optional("name-1")', location='Optional("addr-1")']:
    setSelected(false, false): [name='Optional("name-1")', location='Optional("addr-1")']:
    didSelectRowAtIndexPath: oldRow = '-1' 
    setSelected(false, false): [name='Optional("name-1")', location='Optional("addr-1")']:
    Second click
    (良好:第 1 行未选中且未突出显示)
似乎发生了一些对 setSelected 的额外调用,不确定原因。
(4) 单击 3:打开?
    setSelected(true, false): [name='Optional("name-1")', location='Optional("addr-1")']:
    setSelected(false, false): [name='Optional("name-1")', location='Optional("addr-1")']:
    setSelected(true, false): [name='Optional("name-1")', location='Optional("addr-1")']:
    didSelectRowAtIndexPath: (row = 0)(oldRow = -1)(newRow = 0)[cell.selected = true]
    didSelectRowAtIndexPath => reloadRowsAtIndexPaths 
    setSelected(false, false): [name='Optional("name-1")', location='Optional("addr-1")']:
    setSelected(false, false): [name='Optional("name-1")', location='Optional("addr-1")']:
    cellForRowAtIndexPath: (row = 0)(oldRow = -1)(newRow = 0)[cell.selected = false]
    setSelected(false, false): [name='Optional("name-1")', location='Optional("addr-1")']:
    setSelected(true, false): [name='Optional("name-1")', location='Optional("addr-1")']:
    didSelectRowAtIndexPath: oldRow = '0' 
    (错误:第 1 行仍未选中且未突出显示)
    (无论您点击同一行多少次,图像都与上面完全相同)
    (如果您点击第二行,它会经历同样的循环,一开始似乎有效,然后在第二次点击后不再显示为选中状态)
应该看起来与第一次点击该行相同,但对 setSelected 有额外的调用,最终结果是错误的。

(5) 单击 4:关闭?
    setSelected(true, false): [name='Optional("name-1")', location='Optional("addr-1")']:
    setSelected(false, false): [name='Optional("name-1")', location='Optional("addr-1")']:
    setSelected(true, false): [name='Optional("name-1")', location='Optional("addr-1")']:
    didSelectRowAtIndexPath: (row = 0)(oldRow = 0)(newRow = 0)[cell.selected = true]
    didSelectRowAtIndexPath => didDeselectRowAtIndexPath 
    didDeselectRowAtIndexPath: (row = 0)(oldRow = 0)(newRow = 0)[cell.selected = true]
    didDeselectRowAtIndexPath => reloadRowsAtIndexPaths 
    cellForRowAtIndexPath: (row = 0)(oldRow = 0)(newRow = 0)[cell.selected = false]
    setSelected(false, false): [name='Optional("name-1")', location='Optional("addr-1")']:
    setSelected(false, false): [name='Optional("name-1")', location='Optional("addr-1")']:
    didSelectRowAtIndexPath: oldRow = '-1' 
    setSelected(false, false): [name='Optional("name-1")', location='Optional("addr-1")']:
    (好的:第 1 行未选中且未突出显示,但可能不是出于正确的原因)

那么... 我再一次问 - 你看到我做错了什么了吗?我还应该做些什么来调试它吗?

最佳答案

您发布的内容很多,我很难理解。然而,一个潜在的问题很突出。我认为您想要复选标记附件来指示单元格已被选中,并且您有以下代码:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("resultCell", forIndexPath: indexPath) as! ExistingLocationTableViewCell
    let row  = indexPath.row
    let item = locationList[row]

    cell.nameLabel.text     = item.name
    cell.locationLabel.text = item.address
    cell.accessoryType      = .None // initialize accessory icon?

    return cell
}

然后在 didSelectdidDeselect 中,您正在更改附件。这不是 UITableView 的工作方式。它不记得状态——你必须自己做。在 didSelect 中,您应该存储 indexPath,然后重新加载表。这将通过再次调用 cellForRowAtIndexPath 重绘所有可见单元格。您的代码应决定是否使用类似于以下的代码显示复选标记:

cell.accessoryType = (indexPath == mySelectedIndexPath) ? .Checkmark : .None

mySelectedIndexPath 是您的存储状态。这应该在您的 viewController 中定义,而不是在单元格中 - 当您调用 dequeueReusableCellWithIdentifier 时,您可能会得到一个新的单元格,或者一个已被移出屏幕的现有初始化单元格。每次你得到一个,你必须假设它包含另一行的数据,并适本地设置一切。

关于ios - 如何切换 UITableViewContoller/UITableViewCell 中的选定行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39359111/

相关文章:

ios - 新的 GMSMapView 无法工作,但旧的 GMSMapView 加载正常

ios - 无法将类型 'UITableViewCell' (0x10c111c68) 的值转换为子类

ios - 如何检查用户是否已从设置中启用推送通知?

ios - View 的自动布局相同的宽度和高度?

ios - BSImagePickerViewController 用于快速从图库中选择视频

ios - 如何在 iOS 中标记拖动到达屏幕边界时移动 map 相机?

ios - 从 Storyboard返回到 XIB

ios - 应用程序在 textview.becomeFirstResponder 处崩溃

ios - 如何正确设置导航栏中图像的约束?

ios - Swift:使用 firebase SDK 时使用未解析的标识符 'FDataSnapShot'