当用户在表格视图中滑动单元格时如何创建“更多”按钮(如 ios 7 中的邮件应用程序)
我一直在这里和 Cocoa Touch 论坛中寻找这些信息,但我似乎找不到答案,我希望比我更聪明的人能给我一个解决方案。
我希望当用户滑动表格视图单元格时,显示多个编辑按钮(他默认是删除按钮)。在 iOS 7 的邮件应用程序中,您可以滑动删除,但会显示一个“更多”按钮。
https://i.stack.imgur.com/H6oeX.png
如何实施
看起来 iOS 8 开放了这个 API。 Beta 2 中提供了此类功能的提示。
要使某些东西正常工作,请在 UITableView 的委托上实现以下两种方法以获得所需的效果(请参阅要点以获取示例)。
- tableView:editActionsForRowAtIndexPath:
- tableView:commitEditingStyle:forRowAtIndexPath:
已知的问题
文档说 tableView:commitEditingStyle:forRowAtIndexPath 是:
“不调用使用 UITableViewRowAction 进行编辑操作 - 将调用操作的处理程序。”
但是,没有它,刷卡不起作用。即使方法存根是空白的,它现在仍然需要它。这显然是 beta 2 中的一个错误。
来源
https://twitter.com/marksands/status/481642991745265664 https://gist.github.com/marksands/76558707f583dbb8f870
原始答案:https://stackoverflow.com/a/24540538/870028
更新:
此工作的示例代码(在 Swift 中):http://dropbox.com/s/0fvxosft2mq2v5m/DeleteRowExampleSwift.zip
示例代码在 MasterViewController.swift 中包含这个易于遵循的方法,仅使用此方法,您就可以获得 OP 屏幕截图中显示的行为:
override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [AnyObject]? {
var moreRowAction = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "More", handler:{action, indexpath in
println("MORE•ACTION");
});
moreRowAction.backgroundColor = UIColor(red: 0.298, green: 0.851, blue: 0.3922, alpha: 1.0);
var deleteRowAction = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "Delete", handler:{action, indexpath in
println("DELETE•ACTION");
});
return [deleteRowAction, moreRowAction];
}
我创建了一个新库来实现可滑动按钮,它支持各种转换和可扩展按钮,如 iOS 8 邮件应用程序。
https://github.com/MortimerGoro/MGSwipeTableCell
该库与创建 UITableViewCell 的所有不同方法兼容,并在 iOS 5、iOS 6、iOS 7 和 iOS 8 上进行了测试。
这里是一些转换的示例:
边界过渡:
https://i.stack.imgur.com/W1Fzx.gif
剪辑过渡
https://i.stack.imgur.com/NDO8b.gif
3D 过渡:
https://i.stack.imgur.com/0ySEo.gif
约翰尼的回答是正确的。我只是在objective-c中添加了这个,让初学者(以及我们这些拒绝学习Swift语法的人)更清楚:)
确保您声明了 uitableviewdelegate 并具有以下方法:
-(NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewRowAction *button = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"Button 1" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath)
{
NSLog(@"Action to perform with Button 1");
}];
button.backgroundColor = [UIColor greenColor]; //arbitrary color
UITableViewRowAction *button2 = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"Button 2" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath)
{
NSLog(@"Action to perform with Button2!");
}];
button2.backgroundColor = [UIColor blueColor]; //arbitrary color
return @[button, button2]; //array with all the buttons you want. 1,2,3, etc...
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
// you need to implement this method too or nothing will work:
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES; //tableview must be editable or nothing will work...
}
这是(相当荒谬的)一个私有 API。
以下两个方法是私有的并发送给 UITableView 的委托:
-(NSString *)tableView:(UITableView *)tableView titleForSwipeAccessoryButtonForRowAtIndexPath:(NSIndexPath *)indexPath;
-(void)tableView:(UITableView *)tableView swipeAccessoryButtonPushedForRowAtIndexPath:(NSIndexPath *)indexPath;
它们是不言自明的。
为了改进约翰尼的答案,现在可以使用公共 API 来完成,如下所示:
func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
let moreRowAction = UITableViewRowAction(style: UITableViewRowActionStyle.default, title: "More", handler:{action, indexpath in
print("MORE•ACTION");
});
moreRowAction.backgroundColor = UIColor(red: 0.298, green: 0.851, blue: 0.3922, alpha: 1.0);
let deleteRowAction = UITableViewRowAction(style: UITableViewRowActionStyle.default, title: "Delete", handler:{action, indexpath in
print("DELETE•ACTION");
});
return [deleteRowAction, moreRowAction];
}
我希望你不能等到苹果给你你需要的东西,对吧?所以这是我的选择。
创建一个自定义单元格。里面有两个uiview
1. upper
2. lower
在下部视图中,添加您需要的任何按钮。像任何其他 IBActions 一样处理其操作。你可以决定动画的时间、风格和任何东西。
现在将 uiswipegesture 添加到上视图并在滑动手势上显示您的下视图。我以前做过这个,就我而言,这是最简单的选择。
希望有所帮助。
使用标准 SDK 无法做到这一点。但是,有各种第 3 方解决方案或多或少地模仿 Mail.app 中的行为。其中一些(例如 MCSwipeTableViewCell、DAContextMenuTableViewController、RMSwipeTableViewCell)使用手势识别器检测滑动,其中一些(例如 SWTableViewCell)在标准 UITableViewCellScrollView
(UITableViewCell
的私有子视图)下方放置第二个 UISScrollView其中一些修改了 UITableViewCellScrollView
的行为。
我最喜欢最后一种方法,因为触摸处理感觉最自然。具体来说,MSCMoreOptionTableViewCell 很好。您的选择可能因您的特定需求而异(您是否也需要从左到右的平移,是否需要 iOS 6 兼容性等)。另请注意,这些方法中的大多数都带有负担:如果 Apple 在 UITableViewCell
子视图层次结构中进行更改,它们很容易在未来的 iOS 版本中中断。
不使用任何库的 Swift 3 版本代码:
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
tableView.tableFooterView = UIView(frame: CGRect.zero) //Hiding blank cells.
tableView.separatorInset = UIEdgeInsets.zero
tableView.dataSource = self
tableView.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath)
return cell
}
//Enable cell editing methods.
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
}
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let more = UITableViewRowAction(style: .normal, title: "More") { action, index in
//self.isEditing = false
print("more button tapped")
}
more.backgroundColor = UIColor.lightGray
let favorite = UITableViewRowAction(style: .normal, title: "Favorite") { action, index in
//self.isEditing = false
print("favorite button tapped")
}
favorite.backgroundColor = UIColor.orange
let share = UITableViewRowAction(style: .normal, title: "Share") { action, index in
//self.isEditing = false
print("share button tapped")
}
share.backgroundColor = UIColor.blue
return [share, favorite, more]
}
}
您需要子类 UITableViewCell
和子类方法 willTransitionToState:(UITableViewCellStateMask)state
,每当用户滑动单元格时都会调用该方法。 state
标志会让您知道删除按钮是否正在显示,并在那里显示/隐藏您的更多按钮。
不幸的是,这个方法既没有给你删除按钮的宽度,也没有给你动画时间。因此,您需要将更多按钮的帧和动画时间观察并硬编码到您的代码中(我个人认为 Apple 需要对此做一些事情)。
从 iOS 11 开始,这在 UITableViewDelegate
中公开可用。这是一些示例代码:
迅速
func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let action = UIContextualAction(style: .normal, title: nil) { (_, _, _) in
print("Swipe action tapped")
}
action.image = UIImage(systemName: "plus.slash.minus")
action.backgroundColor = .green
return UISwipeActionsConfiguration(actions: [action])
}
目标 C
- (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath {
UIContextualAction *delete = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive
title:@"DELETE"
handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
NSLog(@"index path of delete: %@", indexPath);
completionHandler(YES);
}];
UIContextualAction *rename = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleNormal
title:@"RENAME"
handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
NSLog(@"index path of rename: %@", indexPath);
completionHandler(YES);
}];
UISwipeActionsConfiguration *swipeActionConfig = [UISwipeActionsConfiguration configurationWithActions:@[rename, delete]];
swipeActionConfig.performsFirstActionWithFullSwipe = NO;
return swipeActionConfig;
}
也提供:
- (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView leadingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath;
文档:https://developer.apple.com/documentation/uikit/uitableviewdelegate/2902367-tableview?language=objc
用于快速编程
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == UITableViewCellEditingStyle.Delete {
deleteModelAt(indexPath.row)
self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
}
else if editingStyle == UITableViewCellEditingStyle.Insert {
println("insert editing action")
}
}
func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [AnyObject]? {
var archiveAction = UITableViewRowAction(style: .Default, title: "Archive",handler: { (action: UITableViewRowAction!, indexPath: NSIndexPath!) in
// maybe show an action sheet with more options
self.tableView.setEditing(false, animated: false)
}
)
archiveAction.backgroundColor = UIColor.lightGrayColor()
var deleteAction = UITableViewRowAction(style: .Normal, title: "Delete",
handler: { (action: UITableViewRowAction!, indexPath: NSIndexPath!) in
self.deleteModelAt(indexPath.row)
self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic);
}
);
deleteAction.backgroundColor = UIColor.redColor()
return [deleteAction, archiveAction]
}
func deleteModelAt(index: Int) {
//... delete logic for model
}
实际 Swift 3 答案
这是您需要的唯一功能。自定义操作不需要 CanEdit 或 CommitEditingStyle 函数。
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let action1 = UITableViewRowAction(style: .default, title: "Action1", handler: {
(action, indexPath) in
print("Action1")
})
action1.backgroundColor = UIColor.lightGray
let action2 = UITableViewRowAction(style: .default, title: "Action2", handler: {
(action, indexPath) in
print("Action2")
})
return [action1, action2]
}
我希望将相同的功能添加到我的应用程序中,在学习了许多不同的教程(raywenderlich 是最好的 DIY 解决方案)之后,我发现 Apple 有自己的UITableViewRowAction
类,非常方便。
您必须将 Tableview 的锅炉点方法更改为:
override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [AnyObject]? {
// 1
var shareAction = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "Share" , handler: { (action:UITableViewRowAction!, indexPath:NSIndexPath!) -> Void in
// 2
let shareMenu = UIAlertController(title: nil, message: "Share using", preferredStyle: .ActionSheet)
let twitterAction = UIAlertAction(title: "Twitter", style: UIAlertActionStyle.Default, handler: nil)
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: nil)
shareMenu.addAction(twitterAction)
shareMenu.addAction(cancelAction)
self.presentViewController(shareMenu, animated: true, completion: nil)
})
// 3
var rateAction = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "Rate" , handler: { (action:UITableViewRowAction!, indexPath:NSIndexPath!) -> Void in
// 4
let rateMenu = UIAlertController(title: nil, message: "Rate this App", preferredStyle: .ActionSheet)
let appRateAction = UIAlertAction(title: "Rate", style: UIAlertActionStyle.Default, handler: nil)
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: nil)
rateMenu.addAction(appRateAction)
rateMenu.addAction(cancelAction)
self.presentViewController(rateMenu, animated: true, completion: nil)
})
// 5
return [shareAction,rateAction]
}
您可以在 This Site 上找到更多相关信息。 Apple 的 own documentation 对于更改背景颜色非常有用:
操作按钮的背景颜色。声明 OBJECTIVE-C @property(nonatomic, copy) UIColor *backgroundColor 讨论 使用此属性指定按钮的背景颜色。如果你没有为这个属性指定一个值,UIKit 会根据 style 属性中的值分配一个默认颜色。可用性 适用于 iOS 8.0 及更高版本。
如果你想改变按钮的字体,那就有点棘手了。我在 SO 上看到过 another post。为了提供代码和链接,这是他们在那里使用的代码。您必须更改按钮的外观。您必须对 tableviewcell 进行特定引用,否则您将在整个应用程序中更改按钮的外观(我不希望这样,但您可能会,我不知道 :))
目标 C:
+ (void)setupDeleteRowActionStyleForUserCell {
UIFont *font = [UIFont fontWithName:@"AvenirNext-Regular" size:19];
NSDictionary *attributes = @{NSFontAttributeName: font,
NSForegroundColorAttributeName: [UIColor whiteColor]};
NSAttributedString *attributedTitle = [[NSAttributedString alloc] initWithString: @"DELETE"
attributes: attributes];
/*
* We include UIView in the containment hierarchy because there is another button in UserCell that is a direct descendant of UserCell that we don't want this to affect.
*/
[[UIButton appearanceWhenContainedIn:[UIView class], [UserCell class], nil] setAttributedTitle: attributedTitle
forState: UIControlStateNormal];
}
迅速:
//create your attributes however you want to
let attributes = [NSFontAttributeName: UIFont.systemFontOfSize(UIFont.systemFontSize())] as Dictionary!
//Add more view controller types in the []
UIButton.appearanceWhenContainedInInstancesOfClasses([ViewController.self])
这是最简单,最精简的版本恕我直言。希望能帮助到你。
更新:这是 Swift 3.0 版本:
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
var shareAction:UITableViewRowAction = UITableViewRowAction(style: .default, title: "Share", handler: {(action, cellIndexpath) -> Void in
let shareMenu = UIAlertController(title: nil, message: "Share using", preferredStyle: .actionSheet)
let twitterAction = UIAlertAction(title: "Twitter", style: .default, handler: nil)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
shareMenu.addAction(twitterAction)
shareMenu.addAction(cancelAction)
self.present(shareMenu,animated: true, completion: nil)
})
var rateAction:UITableViewRowAction = UITableViewRowAction(style: .default, title: "Rate" , handler: {(action, cellIndexpath) -> Void in
// 4
let rateMenu = UIAlertController(title: nil, message: "Rate this App", preferredStyle: .actionSheet)
let appRateAction = UIAlertAction(title: "Rate", style: .default, handler: nil)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
rateMenu.addAction(appRateAction)
rateMenu.addAction(cancelAction)
self.present(rateMenu, animated: true, completion: nil)
})
// 5
return [shareAction,rateAction]
}
shareMenu.
不采用 addAction
方法。谢谢
Swift 4 和 iOS 11+
@available(iOS 11.0, *)
override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let delete = UIContextualAction(style: .destructive, title: "Delete") { _, _, handler in
handler(true)
// handle deletion here
}
let more = UIContextualAction(style: .normal, title: "More") { _, _, handler in
handler(true)
// handle more here
}
return UISwipeActionsConfiguration(actions: [delete, more])
}
这可能会帮助您:
-(NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewRowAction *button = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"Button 1" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath)
{
NSLog(@"Action to perform with Button 1");
}];
button.backgroundColor = [UIColor greenColor]; //arbitrary color
UITableViewRowAction *button2 = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"Button 2" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath)
{
NSLog(@"Action to perform with Button2!");
}];
button2.backgroundColor = [UIColor blueColor]; //arbitrary color
return @[button, button2]; //array with all the buttons you want. 1,2,3, etc...
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
// you need to implement this method too or nothing will work:
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return YES; //tableview must be editable or nothing will work...
}
斯威夫特 4
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let delete = UIContextualAction(style: .destructive, title: "Delete") { (action, sourceView, completionHandler) in
print("index path of delete: \(indexPath)")
completionHandler(true)
}
let rename = UIContextualAction(style: .normal, title: "Edit") { (action, sourceView, completionHandler) in
print("index path of edit: \(indexPath)")
completionHandler(true)
}
let swipeActionConfig = UISwipeActionsConfiguration(actions: [rename, delete])
swipeActionConfig.performsFirstActionWithFullSwipe = false
return swipeActionConfig
}
sourceView
是“显示操作的视图”。有关详细信息,请搜索“UIContextualAction.Handler”。
我使用 tableViewCell 显示多个数据,在单元格上从右向左滑动 () 后会显示两个按钮 Approve 和 reject,有两种方法,第一个是 ApproveFunc,它接受一个参数,另一个是 RejectFunc,它也接受一个论点。
https://i.stack.imgur.com/AgQVl.jpg
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let Approve = UITableViewRowAction(style: .normal, title: "Approve") { action, index in
self.ApproveFunc(indexPath: indexPath)
}
Approve.backgroundColor = .green
let Reject = UITableViewRowAction(style: .normal, title: "Reject") { action, index in
self.rejectFunc(indexPath: indexPath)
}
Reject.backgroundColor = .red
return [Reject, Approve]
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func ApproveFunc(indexPath: IndexPath) {
print(indexPath.row)
}
func rejectFunc(indexPath: IndexPath) {
print(indexPath.row)
}
这是一种有点脆弱的方法,它不涉及私有 API 或构建您自己的系统。您正在对冲您的赌注,即 Apple 不会破坏这一点,并希望他们会发布一个 API,您可以用它来替换这几行代码。
KVO self.contentView.superview.layer.sublayer。在 init 中执行此操作。这是 UIScrollView 的层。你不能 KVO 'subviews'。当子视图发生变化时,在scrollview.subviews 中找到删除确认视图。这是在观察回调中完成的。将该视图的大小加倍并在其唯一子视图的左侧添加一个 UIButton。这也在观察回调中完成。删除确认视图的唯一子视图是删除按钮。 (可选)UIButton 事件应该查找 self.superview 直到找到 UITableView,然后调用您创建的数据源或委托方法,例如 tableView:commitCustomEditingStyle:forRowAtIndexPath:。您可以使用 [tableView indexPathForCell:self] 找到单元格的 indexPath。
这也需要您实现标准的表格视图编辑委托回调。
static char kObserveContext = 0;
@implementation KZTableViewCell {
UIScrollView *_contentScrollView;
UIView *_confirmationView;
UIButton *_editButton;
UIButton *_deleteButton;
}
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
_contentScrollView = (id)self.contentView.superview;
[_contentScrollView.layer addObserver:self
forKeyPath:@"sublayers"
options:0
context:&kObserveContext];
_editButton = [UIButton new];
_editButton.backgroundColor = [UIColor lightGrayColor];
[_editButton setTitle:@"Edit" forState:UIControlStateNormal];
[_editButton addTarget:self
action:@selector(_editTap)
forControlEvents:UIControlEventTouchUpInside];
}
return self;
}
-(void)dealloc {
[_contentScrollView.layer removeObserver:self forKeyPath:@"sublayers" context:&kObserveContext];
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if(context != &kObserveContext) {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
return;
}
if(object == _contentScrollView.layer) {
for(UIView * view in _contentScrollView.subviews) {
if([NSStringFromClass(view.class) hasSuffix:@"ConfirmationView"]) {
_confirmationView = view;
_deleteButton = [view.subviews objectAtIndex:0];
CGRect frame = _confirmationView.frame;
CGRect frame2 = frame;
frame.origin.x -= frame.size.width;
frame.size.width *= 2;
_confirmationView.frame = frame;
frame2.origin = CGPointZero;
_editButton.frame = frame2;
frame2.origin.x += frame2.size.width;
_deleteButton.frame = frame2;
[_confirmationView addSubview:_editButton];
break;
}
}
return;
}
}
-(void)_editTap {
UITableView *tv = (id)self.superview;
while(tv && ![tv isKindOfClass:[UITableView class]]) {
tv = (id)tv.superview;
}
id<UITableViewDelegate> delegate = tv.delegate;
if([delegate respondsToSelector:@selector(tableView:editTappedForRowWithIndexPath:)]) {
NSIndexPath *ip = [tv indexPathForCell:self];
// define this in your own protocol
[delegate tableView:tv editTappedForRowWithIndexPath:ip];
}
}
@end
有一个很棒的库,叫做 SwipeCellKit
,它应该得到更多的认可。在我看来,它比 MGSwipeTableCell
更酷。后者不能完全复制邮件应用程序单元格的行为,而 SwipeCellKit
可以。 Have a look
SwipeCellKit
并留下了深刻的印象......直到我得到了其中一个异常,因为表视图更新之前的行数与更新之后的行数不一样 +/- 行的变化。问题是,我从未更改过我的数据集。因此,如果这不令人担忧,我不知道是什么。所以我决定不使用它,只使用新的 UITableViewDelegate 方法。如果您需要更多自定义,您可以随时覆盖 willBeginEditingRowAt: ....
这是一个简单的解决方案。它能够在 UITableViewCell 中显示和隐藏自定义 UIView。显示逻辑包含在从 UITableViewCell、BaseTableViewCell 扩展的类中。
BaseTableViewCell.h
#import <UIKit/UIKit.h>
@interface BaseTableViewCell : UITableViewCell
@property(nonatomic,strong)UIView* customView;
-(void)showCustomView;
-(void)hideCustomView;
@end
BaseTableViewCell.M
#import "BaseTableViewCell.h"
@interface BaseTableViewCell()
{
BOOL _isCustomViewVisible;
}
@end
@implementation BaseTableViewCell
- (void)awakeFromNib {
// Initialization code
}
-(void)prepareForReuse
{
self.customView = nil;
_isCustomViewVisible = NO;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
-(void)showCustomView
{
if(nil != self.customView)
{
if(!_isCustomViewVisible)
{
_isCustomViewVisible = YES;
if(!self.customView.superview)
{
CGRect frame = self.customView.frame;
frame.origin.x = self.contentView.frame.size.width;
self.customView.frame = frame;
[self.customView willMoveToSuperview:self.contentView];
[self.contentView addSubview:self.customView];
[self.customView didMoveToSuperview];
}
__weak BaseTableViewCell* blockSelf = self;
[UIView animateWithDuration:.5 animations:^(){
for(UIView* view in blockSelf.contentView.subviews)
{
CGRect frame = view.frame;
frame.origin.x = frame.origin.x - blockSelf.customView.frame.size.width;
view.frame = frame;
}
}];
}
}
}
-(void)hideCustomView
{
if(nil != self.customView)
{
if(_isCustomViewVisible)
{
__weak BaseTableViewCell* blockSelf = self;
_isCustomViewVisible = NO;
[UIView animateWithDuration:.5 animations:^(){
for(UIView* view in blockSelf.contentView.subviews)
{
CGRect frame = view.frame;
frame.origin.x = frame.origin.x + blockSelf.customView.frame.size.width;
view.frame = frame;
}
}];
}
}
}
@end
要获得此功能,只需从 BaseTableViewCell 扩展您的表格视图单元格。
接下来,在实现 UITableViewDelegate 的 UIViewController 内部,创建两个手势识别器来处理左右滑动。
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self.tableView registerNib:[UINib nibWithNibName:CUSTOM_CELL_NIB_NAME bundle:nil] forCellReuseIdentifier:CUSTOM_CELL_ID];
UISwipeGestureRecognizer* leftSwipeRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleLeftSwipe:)];
leftSwipeRecognizer.direction = UISwipeGestureRecognizerDirectionLeft;
[self.tableView addGestureRecognizer:leftSwipeRecognizer];
UISwipeGestureRecognizer* rightSwipeRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleRightSwipe:)];
rightSwipeRecognizer.direction = UISwipeGestureRecognizerDirectionRight;
[self.tableView addGestureRecognizer:rightSwipeRecognizer];
}
比添加两个滑动处理程序
- (void)handleLeftSwipe:(UISwipeGestureRecognizer*)recognizer
{
CGPoint point = [recognizer locationInView:self.tableView];
NSIndexPath* index = [self.tableView indexPathForRowAtPoint:point];
UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:index];
if([cell respondsToSelector:@selector(showCustomView)])
{
[cell performSelector:@selector(showCustomView)];
}
}
- (void)handleRightSwipe:(UISwipeGestureRecognizer*)recognizer
{
CGPoint point = [recognizer locationInView:self.tableView];
NSIndexPath* index = [self.tableView indexPathForRowAtPoint:point];
UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:index];
if([cell respondsToSelector:@selector(hideCustomView)])
{
[cell performSelector:@selector(hideCustomView)];
}
}
现在,在 UITableViewDelegate 的 cellForRowAtIndexPath 中,您可以创建自定义 UIView 并将其附加到出列单元格。
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCellTableViewCell* cell = (CustomCellTableViewCell*)[tableView dequeueReusableCellWithIdentifier:@"CustomCellTableViewCell" forIndexPath:indexPath];
NSArray* nibViews = [[NSBundle mainBundle] loadNibNamed:@"CellCustomView"
owner:nil
options:nil];
CellCustomView* customView = (CellCustomView*)[ nibViews objectAtIndex: 0];
cell.customView = customView;
return cell;
}
当然,这种自定义 UIView 的加载方式只是为了这个例子。随心所欲地管理它。
tableView.editing = false
(objc 中的NO
),单元格将“关闭”。