Swift 3 - iOS 10 启用 UITableView "swipe-to-delete"
Swift 3 - iOS 10 UITableView enabling "swipe-to-delete"
有很多关于如何为UITableView启用滑动删除的问题,他们都说同样的事情:
覆盖 tableView(_:commit editingStyle:forRowAt indexPath:)
.
我已经这样做了,但我仍然没有滑动删除功能。我尝试过的事情:
- 在代码和 IB 中将
tableView.allowsMultipleSelectionDuringEditing
设置为 true 和 false。
- 覆盖
tableView(_:canEditRowAt indexPath:)
并返回 true
。
- 覆盖
tableView(_:editingStyleForRowAt indexPath:)
并返回 .delete
。
- 以及以上所有组合。
我使用 FirebaseUI
和自定义 UITableViewCell
来填充 table。这是我的 table 视图控制器:
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?) {
}
}
- 在故事板上,select 视图控制器(视图控制器顶部的黄色部分)。虽然视图控制器是 selected:
选择编辑器 > 嵌入 > 导航控制器。
- 将此添加到您的 viewDidLoad:
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.
}
最近的 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)
}
}
}
有很多关于如何为UITableView启用滑动删除的问题,他们都说同样的事情:
覆盖 tableView(_:commit editingStyle:forRowAt indexPath:)
.
我已经这样做了,但我仍然没有滑动删除功能。我尝试过的事情:
- 在代码和 IB 中将
tableView.allowsMultipleSelectionDuringEditing
设置为 true 和 false。 - 覆盖
tableView(_:canEditRowAt indexPath:)
并返回true
。 - 覆盖
tableView(_:editingStyleForRowAt indexPath:)
并返回.delete
。 - 以及以上所有组合。
我使用 FirebaseUI
和自定义 UITableViewCell
来填充 table。这是我的 table 视图控制器:
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?) {
}
}
- 在故事板上,select 视图控制器(视图控制器顶部的黄色部分)。虽然视图控制器是 selected:
选择编辑器 > 嵌入 > 导航控制器。
- 将此添加到您的 viewDidLoad:
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.
}
最近的 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)
}
}
}