滑动以删除和“更多”按钮(如 iOS 7 上的邮件应用程序)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17254402/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Swipe to Delete and the "More" button (like in Mail app on iOS 7)
提问by Guy Kahlon
How to create a "more" button when user swipe a cell in table view (like mail app in ios 7)
当用户在表格视图中滑动单元格时如何创建“更多”按钮(如 ios 7 中的邮件应用程序)
I have been looking for this information both here and in the Cocoa Touch forum, but I cannot seem to find the answer and I am hoping someone smarter than myself can give me a solution.
我一直在这里和 Cocoa Touch 论坛中寻找这些信息,但我似乎找不到答案,我希望比我更聪明的人能给我一个解决方案。
I would like that when the user swipes a table view cell, to display more than one editing button (he default is the delete button). In the Mail app for iOS 7 you can swipe to delete, but there is a "MORE" button that shows up.
我希望当用户滑动表格视图单元格时,显示多个编辑按钮(他默认是删除按钮)。在 iOS 7 的邮件应用程序中,您可以滑动删除,但会显示一个“更多”按钮。
回答by Johnny
How to Implement
如何实施
It looks like iOS 8 opens up this API. Hints of such functionality are present in Beta 2.
看起来 iOS 8 开放了这个 API。Beta 2 中提供了此类功能的提示。
To get something working, implement the following two methods on your UITableView's delegate to get the desired effect (see gist for an example).
要使某些事情起作用,请在 UITableView 的委托上实现以下两个方法以获得所需的效果(示例请参见要点)。
- tableView:editActionsForRowAtIndexPath:
- tableView:commitEditingStyle:forRowAtIndexPath:
Known Issues
已知的问题
The documentation says tableView:commitEditingStyle:forRowAtIndexPath is:
文档说 tableView:commitEditingStyle:forRowAtIndexPath 是:
"Not called for edit actions using UITableViewRowAction - the action's handler will be invoked instead."
“不使用 UITableViewRowAction 调用编辑操作 - 将调用操作的处理程序。”
However, the swiping doesn't work without it. Even if the method stub is blank, it still needs it, for now. This is most obviously a bug in beta 2.
但是,没有它,滑动就无法工作。即使方法存根是空白的,它现在仍然需要它。这显然是 beta 2 中的一个错误。
Sources
来源
https://twitter.com/marksands/status/481642991745265664https://gist.github.com/marksands/76558707f583dbb8f870
https://twitter.com/marksands/status/481642991745265664 https://gist.github.com/marksands/76558707f583dbb8f870
Original Answer: https://stackoverflow.com/a/24540538/870028
原答案:https: //stackoverflow.com/a/24540538/870028
Update:
更新:
Sample code with this working (In Swift): http://dropbox.com/s/0fvxosft2mq2v5m/DeleteRowExampleSwift.zip
此工作的示例代码(在 Swift 中):http: //dropbox.com/s/0fvxosft2mq2v5m/DeleteRowExampleSwift.zip
The sample code contains this easy-to-follow method in MasterViewController.swift, and with just this method you get the behavior shown in the OP screenshot:
示例代码在 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];
}
回答by MortimerGoro
I have created a new library to implement swippable buttons which supports a variety of transitions and expandable buttons like iOS 8 mail app.
我创建了一个新库来实现可滑动按钮,它支持各种转换和可扩展按钮,如 iOS 8 邮件应用程序。
https://github.com/MortimerGoro/MGSwipeTableCell
https://github.com/MortimerGoro/MGSwipeTableCell
This library is compatible with all the different ways to create a UITableViewCell and its tested on iOS 5, iOS 6, iOS 7 and iOS 8.
该库与创建 UITableViewCell 的所有不同方式兼容,并在 iOS 5、iOS 6、iOS 7 和 iOS 8 上进行了测试。
Here a sample of some transitions:
这是一些转换的示例:
Border transition:
边界过渡:
Clip transition
剪辑过渡
3D Transition:
3D 过渡:
回答by timothykc
Johnny's answer is the right one to upvote. I'm just adding this below in objective-c to make it clearer to beginners (and those of us who refuse to learn Swift syntax :)
约翰尼的答案是正确的投票。我只是在 Objective-c 中添加以下内容,以使初学者(以及我们这些拒绝学习 Swift 语法的人)更清楚:
Make sure you declare the uitableviewdelegate and have the following methods:
确保您声明了 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...
}
回答by Jonathan.
This is (rather ridiculously) a private API.
这是(相当可笑)一个私有 API。
The following two methods are private and sent to the UITableView's delegate:
以下两个方法是私有的,发送给 UITableView 的委托:
-(NSString *)tableView:(UITableView *)tableView titleForSwipeAccessoryButtonForRowAtIndexPath:(NSIndexPath *)indexPath;
-(void)tableView:(UITableView *)tableView swipeAccessoryButtonPushedForRowAtIndexPath:(NSIndexPath *)indexPath;
They are pretty self explanatory.
它们是不言自明的。
回答by Arunabh Das
To improve on Johnny's answer, this can now be done using the public API as follows :
为了改进约翰尼的回答,现在可以使用公共 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];
}
回答by Deepukjayan
I hope you cant wait till apple gives you what ever you need right? So here is my option.
我希望你不能等到苹果给你你需要的东西,对吧?所以这是我的选择。
Create a custom cell. Have two uiviews in it
创建自定义单元格。里面有两个 uiviews
1. upper
2. lower
In lower view, add what ever buttons you need. Deal its actions just like any other IBActions. you can decide the animation time, style and anything.
在下方视图中,添加您需要的任何按钮。像处理任何其他 IBAction 一样处理它的动作。你可以决定动画时间、风格和任何东西。
now add a uiswipegesture to the upper view and reveal your lower view on swipe gesture. I have done this before and its the simplest option as far as I am concerned.
现在将 uiswipegesture 添加到上视图并在滑动手势上显示您的下视图。我以前做过这件事,就我而言,这是最简单的选择。
Hope that help.
希望有所帮助。
回答by Ortwin Gentz
This is not possible using the standard SDK. However there are various 3rd party solutions that more or less imitate the behavior in Mail.app. Some of them (e.g. MCSwipeTableViewCell, DAContextMenuTableViewController, RMSwipeTableViewCell) detect swipes using gesture recognizers, some of them (e.g. SWTableViewCell) put a second UISScrollView below the standard UITableViewCellScrollView
(private subview of UITableViewCell
) and some of them modify the behavior of UITableViewCellScrollView
.
使用标准 SDK 无法做到这一点。然而,有各种 3rd 方解决方案或多或少地模仿 Mail.app 中的行为。其中一些(例如MCSwipeTableViewCell、DAContextMenuTableViewController、RMSwipeTableViewCell)使用手势识别器检测滑动,其中一些(例如SWTableViewCell)在标准UITableViewCellScrollView
( 的私有子视图UITableViewCell
)下方放置了第二个 UISScrollView并且其中一些修改了 的行为UITableViewCellScrollView
。
I like the last approach most since the touch handling feels most natural. Specifically, MSCMoreOptionTableViewCellis good. Your choice may vary depending on your specific needs (whether you need a left-to-right pan, too, whether you need iOS 6 compatibility, etc.). Also be aware that most of these approaches come with a burden: they can easily break in a future iOS version if Apple makes changes in the UITableViewCell
subview hierarchy.
我最喜欢最后一种方法,因为触摸处理感觉最自然。具体来说,MSCMoreOptionTableViewCell是好的。您的选择可能因您的特定需求而异(您是否也需要从左到右的平移,是否需要 iOS 6 兼容性等)。还要注意,这些方法中的大多数都有一个负担:如果 Apple 在UITableViewCell
子视图层次结构中进行更改,它们很容易在未来的 iOS 版本中中断。
回答by mriaz0011
Swift 3 version code without using any library:
不使用任何库的 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]
}
}
回答by Khanh Nguyen
You need to subclass UITableViewCell
and subclass method willTransitionToState:(UITableViewCellStateMask)state
which is called whenever user swipes the cell. The state
flags will let you know if the Delete button is showing, and show/hide your More button there.
您需要对UITableViewCell
方法进行子类化和子类化willTransitionToState:(UITableViewCellStateMask)state
,每当用户滑动单元格时都会调用该方法。这些state
标志会让您知道删除按钮是否正在显示,并在那里显示/隐藏您的更多按钮。
Unfortunately this method gives you neither the width of the Delete button nor the animation time. So you need to observer & hard-code your More button's frame and animation time into your code (I personally think Apple needs to do something about this).
不幸的是,这种方法既没有给你删除按钮的宽度,也没有给你动画时间。因此,您需要将“更多”按钮的框架和动画时间观察并硬编码到您的代码中(我个人认为 Apple 需要对此做些什么)。
回答by Michael Yagudaev
For swift programming
用于快速编程
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
}