簡體   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