繁体   English   中英

使用支持NSFetchedResultsController展开/折叠UITableView部分

[英]Expand/collapse UITableView sections with a backing NSFetchedResultsController

    let frc = NSFetchedResultsController(
        fetchRequest: alertsFetchRequest,
        managedObjectContext: self.moc,
        sectionNameKeyPath: "formattedDateDue",
        cacheName: nil)

当我使用NSFetchedResultsController来记录我的记录时,如何展开和折叠表视图中的部分?

我已经看到很多教程解释了扩展和折叠单元格本身,但没有解释使用获取结果控制器生成的部分。

首先,您需要一个数组来跟踪每个部分是展开还是折叠:

var sectionExpandedInfo : [Bool] = []

在获取结果控制器完成其初始performFetch ,为每个部分填充此数组为true (假设您希望默认情况下展开部分):

sectionExpandedInfo = []
for _ in frc.sections! {
    sectionExpandedInfo.append(true)
}

如果折叠部分,修改numberOfRowsInSection方法以返回零:

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if sectionExpandedInfo[section] { // expanded
        let sectionInfo = self.frc.sections![section]
        return sectionInfo.numberOfObjects
    } else { // collapsed
        return 0
    }
}

要切换是否扩展了一个部分,我使用了一个按钮作为viewForHeaderInSection ,并将部分名称作为标题:

override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    if (self.frc.sections!.count > 0) {
        let sectionInfo = self.frc.sections![section]
        let sectionHeaderButton = UIButton(type: .Custom)
        sectionHeaderButton.backgroundColor = UIColor.redColor()
        sectionHeaderButton.setTitle(sectionInfo.name, forState: .Normal)
        sectionHeaderButton.addTarget(self, action: #selector(MasterViewController.toggleSection(_:)), forControlEvents: .TouchUpInside)
        return sectionHeaderButton
    } else {
        return nil
    }
}

然后在toggleSection方法中我使用标题来确定已经点击了哪个标题按钮,并展开/折叠相应的部分:

func toggleSection(sender: UIButton) {
    for (index, frcSection) in self.frc.sections!.enumerate() {
        if sender.titleForState(.Normal) == frcSection.name {
            sectionExpandedInfo[index] = !sectionExpandedInfo[index]
            self.tableView.reloadSections(NSIndexSet(index: index), withRowAnimation: .Automatic)
        }
    }
}

如果您的FRC插入或删除部分,您需要更新sectionExpandedInfo数组以包含/删除额外部分:

func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {
    switch type {
        case .Insert:
            self.sectionExpandedInfo.insert(true, atIndex: sectionIndex)
            self.tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade)
        case .Delete:
            self.sectionExpandedInfo.removeAtIndex(sectionIndex)
            self.tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade)
        default:
            return
    }
}

同样,这假设您希望默认情况下展开部分。

如果要更改结果集,则需要更改请求中的谓词并再次调用performFetch() 然后,您可以更新您的表格。 但是,这可能会导致性能问题。 您可以考虑使用其他更复杂的技术来管理模型视图绑定,例如为每个扩展的部分设置不同的获取结果控制器。 当用户展开一个部分时,创建一个新的获取结果控制器,只获取该部分的对象并更新表视图。 当用户折叠该部分时,丢弃获取结果控制器。 但是,这可能会使表视图数据源实现变得相当复杂。

斯威夫特4:

这里是Swift 4版本的pbasdf很棒的解决方案:

定义和填充布尔数组:

sectionExpandedInfo = []
   for _ in _fetchedResultsController!.sections! {
      sectionExpandedInfo.append(true)
   }

numberOfRowsInSection方法:

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if sectionExpandedInfo[section] { // expanded
            let sectionInfo = self.fetchedResultsController.sections![section] as NSFetchedResultsSectionInfo
            return sectionInfo.numberOfObjects
        } else { // collapsed
            return 0
        }
    }

在节标题中定义按钮(我必须将toggleSelection参数_:替换为sender:为了使它适用于我:

override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    if (self.fetchedResultsController.sections!.count > 0) {
        let sectionInfo = self.fetchedResultsController.sections![section]
        let sectionHeaderButton = UIButton(type: .custom)
        sectionHeaderButton.backgroundColor = UIColor.red
        sectionHeaderButton.setTitle(sectionInfo.name, for: [])
        sectionHeaderButton.addTarget(self, action: #selector(MasterViewController.toggleSection(sender:)), for: .touchUpInside)
        return sectionHeaderButton
    } else {
        return nil
    }
}

toggleSection函数:

@objc func toggleSection(sender: UIButton) {
        for (index, frcSection) in self.fetchedResultsController.sections!.enumerated() {
            if sender.title(for: []) == frcSection.name {
                sectionExpandedInfo[index] = !sectionExpandedInfo[index]
                self.tableView.reloadSections(NSIndexSet(index: index) as IndexSet, with: .automatic)
            }
        }
    }

插入或删除部分:

func controller(controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {
    switch type {
    case .insert:
        self.sectionExpandedInfo.insert(true, at: sectionIndex)
        self.tableView.insertSections(NSIndexSet(index: sectionIndex) as IndexSet, with: .fade)
    case .delete:
        self.sectionExpandedInfo.remove(at: sectionIndex)
        self.tableView.deleteSections(NSIndexSet(index: sectionIndex) as IndexSet, with: .fade)
    default:
        return
    }
}

再次向pbasdf致敬

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM