在Swift中处理单元重新迭代的问题

时间:2016-01-19 00:57:20

标签: ios swift uitableview

我有一个非常有趣的案例,其中我有两个UITableViews。主要TableViewUITableViewController。每个单元由三部分组成。 Header显示标题,Body在您选择cell时充当手风琴,最后是UITableView使用自定义Cell Identifier但使用与UITableViewControllerparent相同的代理。

现在我遇到的问题是,当用户滚动时,所有标题都会混淆parent uitableview以及child uitableview,我知道它与我的dequeueReusableCellWithIdentifier有关{1}}。

jumbled text

单词developer的位置,即父tableview。混乱的文字that is a sub uitableview。我正在寻找一些关于解决这个问题的最佳解决方案的指导。这就是我在做的事情:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        if tableView == self.tableView {
            // #  Adjust profile picture
        //cell.headerView.profileImage.frame = CGRectMake(0,0, 50, 50)
        cell.headerView.profileImage.image = UIImage(named: "avatar-ph.jpg")
        cell.headerView.profileImage.layer.cornerRadius = 
             cell.headerView.profileImage.frame.size.width / 2

        cell.headerView.profileImage.clipsToBounds = true

         ... do stuff
            cell.detailView.innertableView.dataSource = self

            // This is needed for dequeueing to succeed:
            cell.detailView.innertableView.registerClass(SingleOrderTableViewCell.self, forCellReuseIdentifier: "SingleOrderTableViewCell");

            cell.detailView.innertableView.reloadData()
        }
        else {
// [B] INNER TABLE VIEW
            let cell = tableView.dequeueReusableCellWithIdentifier("SingleOrderTableViewCell", forIndexPath: indexPath) as! SingleOrderTableViewCell


            // #  Setup our data to display
        // ## Title
        cell.title = UITextField (frame:CGRectMake(75, 5, 300, 20));
        cell.title.font = UIFont(name: "System Light", size: 10);
        cell.title.text = drinkName;

        cell.title.textColor = UIColor(netHex:0x362C6B);
        // ## qty
        cell.qty = UITextField (frame:CGRectMake(75, 22.5, 300, 20));
        cell.qty.font = UIFont(name: "System Light", size: 10);
        cell.qty.text = "Qty: " + qty;
        cell.qty.textColor = UIColor.grayColor();


        // #  Add to subframe
        cell.addSubview(cell.title);
        cell.addSubview(cell.qty);
           return cell
        }
}

上面的代码显示了我如何处理两个tableviews的区别并将相应的单元格设置为正确的tableview

现在需要注意的是,此处填充的信息基于从服务器返回的对象。所以我的想法是,它工作正常;但indexPath.row与实际关联的cell相关。

有任何想法或建议吗?

1 个答案:

答案 0 :(得分:1)

有几点意见:

  1. 您使用dequeueReusableCellWithIdentifier(indexPath:)对单元格进行了排队,但您要在cellForRowAtIndexPath中添加子视图。不幸的是,这意味着当重新使用一个单元格时,每次都会添加一个新标签。

    如果您要使用这种以编程方式创建的单元格的方法,则应将子视图添加到UITableViewCell子类“initawakeFromNIB方法中。这些方法只调用一次,当单元格重用于表格中的另一行时,不会再调用这些方法。

  2. 我可能会建议进一步简化这一点,切断Gordian结,而不是以编程方式创建单元格。相反,您可以在故事板中添加原型单元格,然后您根本不需要自己调用addSubview。使用单元原型的过程如下:

    • 创建空白UITableViewCell子类。

    • 将单元格原型添加到tableview单元格中。您可以通过将“表视图单元”从Interface Builder对象库拖到表视图中来完成此操作。 (一般来说,它会为您提供一个单元原型,但您不必这样做。)

    • 在Interface Builder的“Identity Inspector”面板上将单元原型的基类设置为您的UITableViewCell子类。还要在“Attributes Inspector”面板上为该原型单元格提供唯一的故事板标识符。

    • 在设计时在Interface Builder中拖动您想要的任何控件,而不是在运行时以编程方式拖动。

    • 将您在Interface Builder中添加的控件的IBOutlet引用添加到自定义UITableViewCell子类中。

    如果您有两种不同类型的细胞,请为​​每种细胞重复此过程。

  3. 与原始问题无关,而不是在tableview中进行tableview,我建议创建一个包含两个单元格原型的单个tableview,一个用于标题单元格,另一个用于详细单元格。

    然后,您可以在表格视图中为每个可折叠单元格组创建单独的“部分”。然后numberOfRowsInSection将根据组是否折叠确定有多少行。如果它已折叠,只需返回标题单元格1即可。如果它没有折叠,请返回1加上该部分中的详细信息行数。

    因此,当您想要隐藏行时,请更新模型中的某个标志以反映该部分已折叠,然后使用适当的动画调用deleteRowsAtIndexPaths以隐藏行。或者,当您想要显示行时,再次更新模型,然后调用addRowsAtIndexPaths

    例如,请考虑以下事项:

    struct Comedian {
        let name: String
    }
    
    struct Troupe {
        let name: String
        let items: [Comedian]
        var collapsed = false
    }
    
    class ViewController: UITableViewController {
    
        var comedyTroupes = [
            Troupe(name: "The Three Stooges", collapsed: true, items: [
                Comedian(name: "Mo"),
                Comedian(name: "Larry"),
                Comedian(name: "Curly")]
            ),
            Troupe(name: "The Marx Brothers", collapsed: true, items: [
                Comedian(name: "Chico"),
                Comedian(name: "Harpo"),
                Comedian(name: "Groucho"),
                Comedian(name: "Gummo"),
                Comedian(name: "Zeppo")]
            ),
            Troupe(name: "The Smothers Brothers", collapsed: true, items: [
                Comedian(name: "Richard"),
                Comedian(name: "Thomas")]
            ),
            Troupe(name: "Laurel and Hardy", collapsed: true, items: [
                Comedian(name: "Laurel"),
                Comedian(name: "Hardy")]
            ),
            Troupe(name: "Abbott and Costello", collapsed: true, items: [
                Comedian(name: "Abbott"),
                Comedian(name: "Costello")]
            ),
        ]
    
        override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
            return comedyTroupes.count
        }
    
        // if the section is collapsed, we only have the header cell; otherwise we have header cell and detail cells
    
        override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return comedyTroupes[section].collapsed ? 1 : comedyTroupes[section].items.count + 1
        }
    
        // row 0 will be the name of the comedy troupe; the rest of the rows will be the names of the comedians
    
        override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
            if indexPath.row == 0 {
                let cell = tableView.dequeueReusableCellWithIdentifier("HeaderCell", forIndexPath: indexPath) as! HeaderCell
                cell.comedyTroupeLabel.text = comedyTroupes[indexPath.section].name
                return cell
            } else {
                let cell = tableView.dequeueReusableCellWithIdentifier("DetailCell", forIndexPath: indexPath) as! DetailCell
                cell.comedianNameLabel.text = comedyTroupes[indexPath.section].items[indexPath.row - 1].name
                return cell
            }
        }
    
        // if we select header row, update model and then either call
        // `addRowsAtIndexPaths or `deleteRowsAtIndexPaths` as appropriate.
    
        override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
            if indexPath.row == 0 {
                let collapsed = !comedyTroupes[indexPath.section].collapsed
                comedyTroupes[indexPath.section].collapsed = collapsed
                let indexPaths = Array(1 ... comedyTroupes[indexPath.section].items.count).map { NSIndexPath(forRow: $0, inSection: indexPath.section) }
                if collapsed {
                    tableView.deleteRowsAtIndexPaths(indexPaths, withRowAnimation: .Middle)
                } else {
                    tableView.insertRowsAtIndexPaths(indexPaths, withRowAnimation: .Middle)
                }
            } else {
                // do whatever you want if user selects one of the detail cells
            }
        }
    }
    

    产量:

    enter image description here

    现在,每当选择标题行时,我都会折叠并展开详细信息行,但您可以使用所需的任何UI(例如,您可以在标题行单元格上添加一些按钮以打开详细信息行和关闭)。此外,如果你不喜欢这个“额外的标题行”模型,你也可以使用正确的节标题视图(但是你必须跳过箍以将标题视图添加到表视图中,捕获它的点击次数等) 。我认为这个标题单元格和细节单元格方法最简单,尽管不是那么直观。但是,无论如何,我希望这说明你不需要在tableviews中使用tableviews。