以编程方式打开UITableView编辑操作button

我有一个UIPageViewController里面有UITableViewControllers ,并且滑动左手势在UIPageViewController之间改变视图和UITableViewCells手势来打开编辑操作之间冲突,所以我需要显示编辑操作,当某个button被点击细胞。

我的问题是我可以通过编程方式显示编辑操作button,而不是在滑动手势上显示它们吗?

苹果有一个私人的API,可以让你这样做,但是,要注意的是,这可能会让你的应用程序从App Store中被拒绝,除非你使用诸如Method Swizzling之类的方法混淆了所述API的使用。 以下是这样做的步骤:

  1. 创build一个名为PrivateMethodRevealer的协议,允许您访问所需的私有Apple API,即显示和解除编辑操作的协议。 感谢提供这种暴露私人API的方法。 协议中的方法被声明为optional ,所以如果苹果改变方法的名称,应用程序不会崩溃,而是不显示编辑操作。

     @objc protocol PrivateMethodRevealer { optional func setShowingDeleteConfirmation(arg1: Bool) optional func _endSwipeToDeleteRowDidDelete(arg1: Bool) } 

    请注意,虽然这些方法引用了delete ,但它显示了单元格上的所有UITableViewRowAction

  2. 创build一个函数来处理UITableViewCell子类中编辑动作的显示和隐藏(如果有的话),或者在UITableViewCell extension创build方法。 为了说明的目的,我将这个方法showActionsshowActions

  3. 将以下内容添加到您的函数中:

     func showActions() { (superview?.superview as? AnyObject)?._endSwipeToDeleteRowDidDelete?(false) (self as AnyObject).setShowingDeleteConfirmation?(true) } 

    这首先通过在UITableView (这是单元的_endSwipeToDeleteRowDidDelete:视图的超级视图)上调用_endSwipeToDeleteRowDidDelete:_endSwipeToDeleteRowDidDelete:任何可见单元格的编辑动作,然后通过调用_endSwipeToDeleteRowDidDelete:来显示单元格自己的编辑动作。 请注意,我们需要closures其他单元格的操作,因为在编辑操作中显示多行是非常麻烦的。

  4. 如果你愿意的话,你也可以在UIViewController中创build一个closures当前正在编辑的单元格的button。 为此,只需调用以下方法,其中tableView是对UITableView的引用:

     (tableView as AnyObject)?._endSwipeToDeleteRowDidDelete?(false) 

如果您的UIPageViewControllerUITableViewCell之间的滑动手势发生冲突,只需覆盖tableView:editingStyleForRowAtIndexPath:方法返回.None

最后,您的代码可能会产生以下结果 演示视频

编辑 :这是一个快速的方法来隐藏使用方法swizzling你的API的使用。 为了提供这种方法的基本实现,请访问本网站 。 被警告,我不能保证它会工作,因为它是不可能的现场testing。

为此,请使用以下代码replace协议,无论您在哪里调用setShowingDeleteConfirmation(true)_endSwipeToDeleteRowDidDelete(false)showRowActions()将其replace为showRowActions()hideRowActions() 。 这种方法似乎有一些意想不到的效果,例如UITableViewCell不响应用户交互,而编辑操作是可见的。

 extension UITableViewCell { func showRowActions(arg1: Bool = true) {} public override static func initialize() { struct Static { static var token: dispatch_once_t = 0 } guard self === UITableViewCell.self else {return} dispatch_once(&Static.token) { let hiddenString = String(":noitamrifnoCeteleDgniwohStes".characters.reverse()) let originalSelector = NSSelectorFromString(hiddenString) let swizzledSelector = #selector(showRowActions(_:)) let originalMethod = class_getInstanceMethod(self, originalSelector) let swizzledMethod = class_getInstanceMethod(self, swizzledSelector) class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)) method_exchangeImplementations(originalMethod, swizzledMethod) } } } extension UITableView { func hideRowActions(arg1: Bool = false) {} public override static func initialize() { struct Static { static var token: dispatch_once_t = 0 } guard self === UITableView.self else {return} dispatch_once(&Static.token) { let hiddenString = String(":eteleDdiDwoReteleDoTepiwSdne_".characters.reverse()) let originalSelector = NSSelectorFromString(hiddenString) let swizzledSelector = #selector(hideRowActions(_:)) let originalMethod = class_getInstanceMethod(self, originalSelector) let swizzledMethod = class_getInstanceMethod(self, swizzledSelector) class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)) method_exchangeImplementations(originalMethod, swizzledMethod) } } } 

我和kabiroberai在寻找这个答案的解决scheme时是一样的,但是采用了两种不同的协议,而不是一个可能被误用的Objective-C / NSObject协议。 这也防止了必须使协议方法可选。

首先,创build两个独立的协议来公开UITableViewUITableViewCell上的私有方法。 我通过挖掘每个类的私人标题 ,发现了这些。

 @objc protocol UITableViewCellPrivate { func setShowingDeleteConfirmation(arg1: Bool) } @objc protocol UITableViewPrivate { func _endSwipeToDeleteRowDidDelete(arg1: Bool) } 

cellForRowAtIndexPath ,保留对要显示编辑操作的单元(或多个单元)的引用:

 class MyTableViewController: UITableViewController { var cell: UITableViewCell? // ... override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("Cell")! // ... if indexPath.row == 1 { self.cell = cell } return cell } } 

现在,开始私人的方法。 我使用了performSelector:withObject:afterDelay ,或者你可以使用一个button。

 override func viewDidLoad() { super.viewDidLoad() self.performSelector(#selector(showActionsForCell), withObject: nil, afterDelay: 2.0) } func showActionsForCell() { if let cell = cell { let cellPrivate = unsafeBitCast(cell, UITableViewCellPrivate.self) let tableViewPrivate = unsafeBitCast(self.tableView, UITableViewPrivate.self) // Dismiss any other edit actions that are open tableViewPrivate._endSwipeToDeleteRowDidDelete(false) // Open the edit actions for the selected cell cellPrivate.setShowingDeleteConfirmation(true) } } 

直接调用unsafeBitCast是危险的。 为了安全起见,请检查您的UITableViewUITableViewCell响应这些select器,或者使这些函数成为可选项。

在我的情况(迅速3,iOS11) MGSwipeTableCell工程完美。 您可以在中configuration通话的button

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: prettyIdentifier, for: indexPath) cell.allowsButtonsWithDifferentWidth = true cell.rightButtons = [MGSwipeButton(title: "Delete\npermanently", backgroundColor: #colorLiteral(red: 0.9745360017, green: 0.7205639482, blue: 0.3932176828, alpha: 1)), MGSwipeButton(title: "Undo",backgroundColor: .black)] cell.rightSwipeSettings.transition = .rotate3D cell.delegate = self return cell } 

代替

 func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {...} 

并接触到

 extension RecordingViewController: MGSwipeTableCellDelegate { func swipeTableCell(_ cell: MGSwipeTableCell, tappedButtonAt index: Int, direction: MGSwipeDirection, fromExpansion: Bool) -> Bool { cell.hideSwipe(animated: true) // do your stuff here like if index == 0 { print("right button") } return true } } 

在你的button点击事件,你可以请尝试下面的function。

 func setEditing(_ editing: Bool, animated animated: Bool) 

这是函数在swift语法中。

根据苹果开发者支持网站,它将做以下事情,

当您调用此方法的值设置为true编辑值,并且UITableViewCell对象被configuration为具有控件时,单元格在每个单元格的左侧显示插入(绿色加号)或删除控件(红色减号),并重新sorting控制在右侧。 当调用UITableView的setEditing:animated:方法时,在每个可见单元格上调用此方法。 调用此方法的编辑设置为false将删除单元格中的控件。

希望这回答了这个问题。

使用IBAction或其他方法设置表视图编辑:

 @IBAction func editOn(sender: UIBarButtonItem) { self.tableView.setEditing(true, animated: true) } 

你可以使用UITableViewController的方法:

 // Override to support conditional editing of the table view. override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool { // Return false if you do not want the specified item to be editable. return true } 

而这个方法是编辑的动作:

 override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? { let action = UITableViewRowAction(style: .Default, title: "Delete") { (rowAction: UITableViewRowAction, indexPAth: NSIndexPath) in //code for delete print("Delete") } let action2 = UITableViewRowAction(style: .Normal, title: "Share") { (rowAction: UITableViewRowAction, indexPAth: NSIndexPath) in //code for share print("Share") } return [action, action2] } 

希望能帮助到你。