Swift 3 - 支持“刷卡删除”的iOS 10 UITableView

时间:2017-01-05 23:51:06

标签: ios swift uitableview firebase firebaseui

关于如何为UITableView启用滑动删除有很多问题,他们都说同样的事情:

覆盖tableView(_:commit editingStyle:forRowAt indexPath:)

除此之外,我已经完成了这项工作,而且我仍然没有刷卡删除功能。我尝试过的事情:

  1. 在代码和IB中将tableView.allowsMultipleSelectionDuringEditing设置为true和false。
  2. 覆盖tableView(_:canEditRowAt indexPath:)并返回true
  3. 覆盖tableView(_:editingStyleForRowAt indexPath:)并返回.delete
  4. 以上各项组合。
  5. 我正在使用FirebaseUI和自定义UITableViewCell来填充表格。这是我的表视图控制器:

    import UIKit
    import FirebaseDatabaseUI
    
    class ScheduleViewController: UITableViewController {
    
        private let TAG = String(describing: ScheduleViewController.self)
    
        private var dataSource: FUITableViewDataSource!
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            dataSource = self.tableView.bind(to: DataManager.instance.habitsQuery(),
                                             populateCell: populateCell())
    
            self.tableView.dataSource = dataSource
    
            // Automatically resize table cells to fit its content.
            self.tableView.estimatedRowHeight = ScheduleTableViewCell.HEIGHT
            self.tableView.rowHeight = UITableViewAutomaticDimension
    
            // I have also
            self.tableView.allowsMultipleSelectionDuringEditing = false
        }
    
        func populateCell() -> (UITableView, IndexPath, FIRDataSnapshot) -> UITableViewCell {
            return { tableView, indexPath, snapshot in
                let cell =
                    tableView.dequeueReusableCell(withIdentifier: ScheduleTableViewCell.IDENTIFIER,
                                                  for: indexPath) as! ScheduleTableViewCell
    
                if let dict = snapshot.value as? Dictionary<String, Any?> {
                    cell.set(habit: Habit(withKey: snapshot.key, from: dict))
                } else {
                    Log.e(self.TAG, "Invalid data returned from Firebase.")
                }
    
                return cell
            }
        }
    
        // MARK: TableView Delegate
    
        override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
            return true
        }
    
        override func tableView(_ tableView: UITableView,
                                editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle
        {
            return .delete
        }
    
        override func tableView(_ tableView: UITableView,
                                commit editingStyle: UITableViewCellEditingStyle,
                                forRowAt indexPath: IndexPath)
        {
    
        }
    
        // MARK: - Navigation
    
        override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        }
    
    }
    

2 个答案:

答案 0 :(得分:7)

最近的FirebaseUI更新打破了原来的答案。

更新的答案:

只需将FUITableViewDataSource子类化为实现自定义UITableViewDataSource功能,然后将子类绑定到UITableView

FUITableViewDataSource子类:

import UIKit
import FirebaseDatabaseUI

class EditableTableDataSource: FUITableViewDataSource {

    /// Called to populate each cell in the UITableView.
    typealias PopulateCellBlock = (UITableView, IndexPath, FIRDataSnapshot) -> UITableViewCell

    /// Called to commit an edit to the UITableView.
    typealias CommitEditBlock = (UITableView, UITableViewCellEditingStyle, IndexPath) -> Void

    private let commitEditBlock: CommitEditBlock?

    /// A wrapper around FUITableViewDataSource.init(query:view tableView:populateCell:), with the
    /// addition of a CommitEditBlock.
    public init(query: FIRDatabaseQuery,
                populateCell: @escaping PopulateCellBlock,
                commitEdit: @escaping CommitEditBlock)
    {
        commitEditBlock = commitEdit
        super.init(collection: FUIArray.init(query: query), populateCell: populateCell)
    }

    override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        return true
    }

    override func tableView(_ tableView: UITableView,
                            commit editingStyle: UITableViewCellEditingStyle,
                            forRowAt indexPath: IndexPath)
    {
        if (commitEditBlock != nil) {
            commitEditBlock!(tableView, editingStyle, indexPath)
        }
    }

}

extension UITableView {

    /// Creates a data source, binds it to the table view, and returns it. Note that this is the
    /// `EditableTableViewDataSource` equivalent of the 
    /// `FUITableViewDataSource.bind(to:populateCell:)` method.
    ///
    /// - parameters:
    ///   - to:             The Firebase query to bind to.
    ///   - populateCell:   A closure that's called to populate each cell.
    ///   - commitEdit:     A closure that's called when the user commits some kind of edit. Maps to
    ///                     `tableView(:commit:forRowAt:)`.
    func bind(to query: FIRDatabaseQuery,
              populateCell: @escaping EditableTableDataSource.PopulateCellBlock,
              commitEdit: @escaping EditableTableDataSource.CommitEditBlock)
        -> EditableTableDataSource
    {
        let dataSource = EditableTableDataSource(query: query,
                                                 populateCell: populateCell,
                                                 commitEdit: commitEdit)
        dataSource.bind(to: self)
        return dataSource
    }

}

用法:

import UIKit
import FirebaseDatabaseUI

class ScheduleViewController: UITableViewController {

    private let TAG = String(describing: ScheduleViewController.self)

    private var dataSource: FUITableViewDataSource!
    private var dataManager: DataManager!

    override func viewDidLoad() {
        super.viewDidLoad()

        dataManager = AppManager.defaultInstance.dataManager()

        dataSource = tableView.bind(
            to: dataManager.scheduledHabitsQuery(),
            populateCell: populateCellBlock(),
            commitEdit: commitEditBlock())
    }


    // MARK: TableView Data Source

    func populateCellBlock() -> EditableTableDataSource.PopulateCellBlock {
        return { tableView, indexPath, snapshot in
            let cell = ScheduledHabitTableViewCell.from(tableView: tableView, at: indexPath)
            cell.set(habit: ScheduledHabit(fromSnapshot: snapshot))
            return cell
        }
    }

    func commitEditBlock() -> EditableTableDataSource.CommitEditBlock {
        return { tableView, editingStyle, indexPath in
            if (editingStyle != .delete) {
                return
            }

            // Delete the data from Firebase.
            let snapshot = self.dataSource.snapshot(at: indexPath.row)
            self.dataManager.moveToTrash(ScheduledHabit(fromSnapshot: snapshot))

            // Deleting the table view row is done automatically by the FirebaseUI data source.
        }
    }


    // MARK: - Navigation

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    }

}

原始答案:

解决方案是继承FUITableViewDataSource并覆盖所需的UITableViewDataSource方法。之后一切都很完美。

import UIKit
import FirebaseDatabaseUI

class FUIEditableTableViewDataSource: FUITableViewDataSource {

    /// Called to populate each cell in the UITableView.
    typealias PopulateCellBlock = (UITableView, IndexPath, FIRDataSnapshot) -> UITableViewCell

    /// Called to commit an edit to the UITableView.
    typealias CommitEditBlock = (UITableView, UITableViewCellEditingStyle, IndexPath) -> Void

    private let commitEditBlock: CommitEditBlock?

    /// A wrapper around FUITableViewDataSource.init(query:view tableView:populateCell:), with the
    /// addition of a CommitEditBlock.
    public init(query: FIRDatabaseQuery,
                tableView: UITableView,
                populateCell: @escaping PopulateCellBlock,
                commitEdit: @escaping CommitEditBlock)
    {
        commitEditBlock = commitEdit
        super.init(query: query, view: tableView, populateCell: populateCell)
    }

    override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        return true
    }

    override func tableView(_ tableView: UITableView,
                            commit editingStyle: UITableViewCellEditingStyle,
                            forRowAt indexPath: IndexPath)
    {
        if (commitEditBlock != nil) {
            commitEditBlock!(tableView, editingStyle, indexPath)
        }
    }

}

答案 1 :(得分:0)

  1. 在情节提要板上,选择视图控制器(视图控制器顶部的黄色控件)。选择视图控制器时:
  2. 选择编辑器&gt;嵌入&gt;导航控制器。

    1. 将此添加到viewDidLoad:
    2. navigationItem.leftBarButtonItem = editButtonItem

      所以你的viewDidLoad应该是这样的:

      override func viewDidLoad() {
          super.viewDidLoad()
      
          // Use the edit button item provided by the table view controller.
          navigationItem.leftBarButtonItem = editButtonItem
      
          // Load the data.
      }
      

      阅读本文:https://developer.apple.com/library/content/referencelibrary/GettingStarted/DevelopiOSAppsSwift/ImplementEditAndDeleteBehavior.html#//apple_ref/doc/uid/TP40015214-CH9-SW1