前言

在我们的app开发当中,经常会用到UITableView 的左滑删除的功能,通常的话效果如下

但有时候系统现有的功能并不能完全满足我们的开发需求,这样就需要我们在其现有的功能基础上自定义我们所需要的功能了。下图是在项目中自定义的按钮(只是修改了按钮的frame而已)。

然后我就总结了一下根据不同的需求自定义不同的按钮。

一、系统默认左滑删除按钮

如果你对左滑删除按钮的要求不高,仅仅只是实现UITableView上cell的左滑删除功能,那在UITableView的代理方法中添加以下两种方法便可实现需求:

//使用系统默认的删除按钮
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
 if (editingStyle == UITableViewCellEditingStyleDelete){

 }
}
//自定义系统默认的删除按钮文字
- (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath {
 return @"自定义按钮”;
}

效果如下所示:


系统自带

虽然这样能基本实现功能,但是我们发现右边的按钮和左边的黄色区域的高度并不一样。这是因为右边按钮是和UITableViewCell的高度一致,而左边的黄色区域只是一张图片而已,其高度设置和UITableViewCell的高度并不一致,才会导致这样的布局出现。如果我们想要删除按钮和左边图片一样的高度,那我们就需要自定义删除按钮的高度了。

二、自定义左滑删除按钮

如果我们想要实现不止一个自定义按钮的功能,那我们就需要在UITableView代理方法- (NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {}中添加我们所需要的多个按钮了。如下是在不同的cell上添加一个或两个左滑按钮:

//自定义多个左滑菜单选项
- (NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {
 UITableViewRowAction *deleteAction;
 deleteAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"删除" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath) {
 [tableView setEditing:NO animated:YES];//退出编辑模式,隐藏左滑菜单
 }];
 if (indexPath.row == 1) {//在不同的cell上添加不同的按钮
 UITableViewRowAction *shareAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"分享" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath) {
  [tableView setEditing:NO animated:YES];//退出编辑模式,隐藏左滑菜单
 }];
 shareAction.backgroundColor = [UIColor blueColor];
 return @[deleteAction,shareAction];
 }
 return @[deleteAction];
}

在上述代理方法中我们就可以实现在cell中添加一个或多个左滑按钮了,根据点击不同的按钮实现不同的响应方法便可。其中[tableView setEditing:NO animated:YES];方法可以在点击按钮之后退出编辑模式并隐藏左滑菜单。但如果我们想要修改按钮的其他属性如标题、背景颜色怎么办?点击进入UITableViewRowAction类中,我们会发现以下属性和方法:

@interface UITableViewRowAction : NSObject <NSCopying>

  (instancetype)rowActionWithStyle:(UITableViewRowActionStyle)style title:(nullable NSString *)title handler:(void (^)(UITableViewRowAction *action, NSIndexPath *indexPath))handler;

@property (nonatomic, readonly) UITableViewRowActionStyle style;
@property (nonatomic, copy, nullable) NSString *title;
@property (nonatomic, copy, nullable) UIColor *backgroundColor; // default background color is dependent on style
@property (nonatomic, copy, nullable) UIVisualEffect* backgroundEffect;

@end

其中 @property (nonatomic, readonly) UITableViewRowActionStyle style;是指设置所添加按钮父视图的背景颜色以及按钮字体颜色:

typedef NS_ENUM(NSInteger, UITableViewRowActionStyle) {
 UITableViewRowActionStyleDefault = 0,//红底白字
 UITableViewRowActionStyleDestructive = UITableViewRowActionStyleDefault,
 UITableViewRowActionStyleNormal//灰底白字
} NS_ENUM_AVAILABLE_IOS(8_0) __TVOS_PROHIBITED;

@property (nonatomic, copy, nullable) UIVisualEffect* backgroundEffect;提供了一个背景模糊效果,有兴趣的可以自行研究一下。

上述的方法和属性只能满足我们的部分需求,如果我们想要改变按钮的大小或者设置带图片的按钮怎么办?那就需要我们在视图中找到我们所要修改的按钮,并设置它的各种属性。由于在iOS8-10和iOS11下自定义按钮处在不同的视图层次中,所以需要我们先了解UITableView上的视图层次。下图为对比:

左iOS10/右iOS11(Xcode9中)

从对比图中可以看出:

(1).iOS10下视图层次为:UITableView -> UITableViewCell -> UITableViewCellDeleteConfirmationView -> _UITableViewCellActionButton,我们所需自定义的按钮视图UITableViewCellDeleteConfirmationView(左图中红框处)是UITableViewCell的子视图。

(2).iOS11下视图层次为:在Xcode 8中编译为: UITableView -> UITableViewWrapperView -> UISwipeActionPullView -> UISwipeActionStandardButton;

在Xcode 9中编译为: UITableView -> UISwipeActionPullView -> UISwipeActionStandardButton。(iOS11中用Xcode 8和Xcode 9中编译有略微的差别),我们所需自定义的按钮视图UISwipeActionPullView(右图中红框处)是UITableView的子视图。

由于不同系统下的视图层次不一样,因此我们在项目中需要根据不同的代码去同时适配iOS8-10和iOS11。
在iOS8-10中( 以下均在Xcode 9中编译):

在该系统下由于我们所需自定义的按钮视图UITableViewCellDeleteConfirmationView是UITableViewCell的子视图,所以我们在自定义UITableViewCell子类中遍历它的subviews即可。代码如下:

- (void)layoutSubviews {
 /**自定义设置iOS8-10系统下的左滑删除按钮大小*/
 for (UIView * subView in self.subviews) {
 if ([subView isKindOfClass:NSClassFromString(@"UITableViewCellDeleteConfirmationView")]) {
  subView.backgroundColor = [UIColor clearColor];//去掉默认红色背景
  //设置按钮frame
  CGRect cRect = subView.frame;
  cRect.origin.y = self.contentView.frame.origin.y   10;
  cRect.size.height = self.contentView.frame.size.height - 20;
  subView.frame = cRect;
  //自定义按钮的文字大小
  if (subView.subviews.count == 1 && self.indexPath.section == 0) {//表示有一个按钮
  UIButton * deleteButton = subView.subviews[0];
  deleteButton.titleLabel.font = [UIFont systemFontOfSize:20];
  }
  //自定义按钮的图片
  if (subView.subviews.count == 1 && self.indexPath.section == 1) {//表示有一个按钮
  UIButton * deleteButton = subView.subviews[0];
  [deleteButton setImage:[UIImage imageNamed:@"login_btn_message"] forState:UIControlStateNormal];
  [deleteButton setTitle:@"" forState:UIControlStateNormal];
  }
  //自定义按钮的文字图片
  if (subView.subviews.count >= 2 && self.indexPath.section == 0) {//表示有两个按钮
  UIButton * deleteButton = subView.subviews[1];
  UIButton * shareButton = subView.subviews[0];
  [deleteButton setTitle:@"" forState:UIControlStateNormal];
  [shareButton setTitle:@"" forState:UIControlStateNormal];
  [self setUpDeleteButton:deleteButton];
  [self setUpShareButton:shareButton];
  }
 }
 }
}

在iOS11中:

在该系统下由于我们所需自定义的按钮视图UISwipeActionPullView是UITableView的子视图,所以我们可以在控制器中自定义UITableView子类中遍历它的subviews即可(以下方法是写在UITableView的代理方法- (void)tableView:(UITableView *)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath中的,该代理方法每次会在开始左滑按钮前调用)。代码如下:

/**自定义设置iOS11系统下的左滑删除按钮大小*/
//开始编辑左滑删除
- (void)tableView:(UITableView *)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath {
 NSInteger section = indexPath.section;
 if (@available(iOS 11.0, *)) {
  for (UIView * subView in self.customTableView.subviews) {
   if ([subView isKindOfClass:NSClassFromString(@"UISwipeActionPullView")]) {
    subView.backgroundColor = [UIColor clearColor];//如果自定义只有一个按钮就要去掉按钮默认红色背景
    //设置按钮frame
    for (UIView * sonView in subView.subviews) {
     if ([sonView isKindOfClass:NSClassFromString(@"UISwipeActionStandardButton")]) {
      CGRect cRect = sonView.frame;
      cRect.origin.y = sonView.frame.origin.y   10;
      cRect.size.height = sonView.frame.size.height - 20;
      sonView.frame = cRect;
     }
    }
    //自定义按钮的文字大小
    if (subView.subviews.count == 1 && section == 0) {//表示有一个按钮
     UIButton * deleteButton = subView.subviews[0];
     deleteButton.titleLabel.font = [UIFont systemFontOfSize:20];
    }
    //自定义按钮的图片
    if (subView.subviews.count == 1 && section == 1) {//表示有一个按钮
     UIButton * deleteButton = subView.subviews[0];
     [deleteButton setImage:[UIImage imageNamed:@"login_btn_message"] forState:UIControlStateNormal];;
    }
    //自定义按钮的文字图片
    if (subView.subviews.count >= 2 && section == 0) {//表示有两个按钮
     UIButton * deleteButton = subView.subviews[1];
     UIButton * shareButton = subView.subviews[0];
     [self setUpDeleteButton:deleteButton];
     [self setUpShareButton:shareButton];
    }
   }
  }
 }
}

如果我们想在左滑删除结束后实现一些功能,我们可以在UITableView中实现以下代理方法:

//结束编辑左滑删除
- (void)tableView:(UITableView *)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath {

}
如果我们想分别设置UITableViewCell是否需要实现左滑功能,可以在下面代理方法中实现:

//判断是否显示左滑删除
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
 return YES;
}

在不同系统下分别添加以上代码即可实现我们所需要的自定义左滑删除按钮,效果图如下:


以上是我总结整理的在不同系统下的自定义UITableView左滑删除功能。

如有不足之处,欢迎指正交流,Demo地址:左滑删除 (本地下载)

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对Devmax的支持。

iOS自定义UITableView实现不同系统下的左滑删除功能详解的更多相关文章

  1. ios – UITableView和Cell Reuse

    这是我的CustomCell类的init方法解决方法如果没有要显示的图像,则必须清除图像视图:

  2. ios – fetchedResultsController.fetchedObjects.count = 0但它充满了对象

    我正在使用相当标准的fetchedResultsController实现来输出tableView.在-viewDidLoad的最后,我正在进行第一次调用:这是我的fetchedResultsController:我的tableView方法:所以,问题是:在_fetchedResultsController.fetchedobjects.count的日志中等于0,但在视觉上tableView充满了对

  3. ios – UITableView在滚动时阻止重新加载

    或者你能想象一个防止这种行为的好方法吗?解决方法抱歉,我没有足够的声誉来添加评论,因此在单独的答案中回答您的上一个问题.-performSelector:withObject:afterDelay:延迟为0.0秒不会立即执行给定的选择器,而是在当前的RunloopCycle结束后和给定的延迟之后执行它.-performSelector:withObject:添加到当前Runloop循环中并执行.这与直接调用该方法相同.因此,使用-performSelector:withObject:afterDelay:

  4. ios – 在Swift中通过标记访问UITableViewCell内部的不同视图

    我正在尝试使用swift为iOS8制作应用程序.这里的目标是制作一种新闻源.此Feed显示来自用户的帖子,其遵循特定模式.我想过使用UITableView,其中每个单元格都遵循自定义布局.当我尝试访问其中的文本标签时出现问题.我尝试通过它的标签访问它,但是当我这样做时,整个应用程序崩溃了.报告的错误是“Swift动态转换失败”,我使用以下代码访问视图:难道我做错了什么?解决方法我认为问题是标签0.所有视图都是默认值0.所以尝试另一个标签值.

  5. ios – 如何实现`prepareForReuse`?

    解决方法尝试将此添加到您的MGSwipeTableCell.m:

  6. ios – 在UITableView上轻扫以删除以使用UIPanGestureRecognizer

    我使用以下代码将UIPanGuestureRecognizer添加到整个视图中:在主视图中我有一个UITableView,它有这个代码来启用滑动删除功能:只有RUNNING1打印到日志中,并且“删除”按钮不会显示.我相信其原因是UIPanGestureRecognizer,但我不确定.如果这是正确的,我该如何解决这个问题.如果这不正确,请提供原因并解决.谢谢.解决方法从document:Ifage

  7. viewWillAppear vs Viewdidload ios

    使用iOS导航应用程序的代码时,我遇到了麻烦:我在哪里可以为UITableView设置方法“initdata”?请帮帮我.解决方法您可以根据应用程序的需求放置initData,如果您的表需要每次使用新数据加载数据,那么它应该在否则,如果表需要通过单个数据重新加载,该数据不会发生变化或者没有对数据执行任何编辑操作,则应使用

  8. ios tableView reloadRowsAtIndexPaths无效

    解决方法包裹它怎么样?希望这可以帮助.

  9. ios – 我的表视图在滚动时在SWIFT中重用所选单元格

    实例变量

  10. ios – 重新加载表动画

    因此,当用户点击我的表格中的单元格时,我实际上并没有推送到新的视图控制器,而只是重新加载该tableView中的数据.但是,我希望得到一个效果类似于我推动新视图控制器时的效果.有没有人知道我如何将旧内容从屏幕上的旧内容和新内容放到屏幕上以获取整个表格?

随机推荐

  1. iOS实现拖拽View跟随手指浮动效果

    这篇文章主要为大家详细介绍了iOS实现拖拽View跟随手指浮动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  2. iOS – genstrings:无法连接到输出目录en.lproj

    使用我桌面上的项目文件夹,我启动终端输入:cd然后将我的项目文件夹拖到终端,它给了我路径.然后我将这行代码粘贴到终端中找.-name*.m|xargsgenstrings-oen.lproj我在终端中收到此错误消息:genstrings:无法连接到输出目录en.lproj它多次打印这行,然后说我的项目是一个目录的路径?没有.strings文件.对我做错了什么的想法?

  3. iOS 7 UIButtonBarItem图像没有色调

    如何确保按钮图标采用全局色调?解决方法只是想将其转换为根注释,以便为“回答”复选标记提供更好的上下文,并提供更好的格式.我能想出这个!

  4. ios – 在自定义相机层的AVFoundation中自动对焦和自动曝光

    为AVFoundation定制图层相机创建精确的自动对焦和曝光的最佳方法是什么?

  5. ios – Xcode找不到Alamofire,错误:没有这样的模块’Alamofire’

    我正在尝试按照github(https://github.com/Alamofire/Alamofire#cocoapods)指令将Alamofire包含在我的Swift项目中.我创建了一个新项目,导航到项目目录并运行此命令sudogeminstallcocoapods.然后我面临以下错误:搜索后我设法通过运行此命令安装cocoapodssudogeminstall-n/usr/local/bin

  6. ios – 在没有iPhone6s或更新的情况下测试ARKit

    我在决定下载Xcode9之前.我想玩新的框架–ARKit.我知道要用ARKit运行app我需要一个带有A9芯片或更新版本的设备.不幸的是我有一个较旧的.我的问题是已经下载了新Xcode的人.在我的情况下有可能运行ARKit应用程序吗?那个或其他任何模拟器?任何想法或我将不得不购买新设备?解决方法任何iOS11设备都可以使用ARKit,但是具有高质量AR体验的全球跟踪功能需要使用A9或更高版本处理器的设备.使用iOS11测试版更新您的设备是必要的.

  7. 将iOS应用移植到Android

    我们制作了一个具有2000个目标c类的退出大型iOS应用程序.我想知道有一个最佳实践指南将其移植到Android?此外,由于我们的应用程序大量使用UINavigation和UIView控制器,我想知道在Android上有类似的模型和实现.谢谢到目前为止,guenter解决方法老实说,我认为你正在计划的只是制作难以维护的糟糕代码.我意识到这听起来像很多工作,但从长远来看它会更容易,我只是将应用程序的概念“移植”到android并从头开始编写.

  8. ios – 在Swift中覆盖Objective C类方法

    我是Swift的初学者,我正在尝试在Swift项目中使用JSONModel.我想从JSONModel覆盖方法keyMapper,但我没有找到如何覆盖模型类中的Objective-C类方法.该方法的签名是:我怎样才能做到这一点?解决方法您可以像覆盖实例方法一样执行此操作,但使用class关键字除外:

  9. ios – 在WKWebView中获取链接URL

    我想在WKWebView中获取tapped链接的url.链接采用自定义格式,可触发应用中的某些操作.例如HTTP://我的网站/帮助#深层链接对讲.我这样使用KVO:这在第一次点击链接时效果很好.但是,如果我连续两次点击相同的链接,它将不报告链接点击.是否有解决方法来解决这个问题,以便我可以检测每个点击并获取链接?任何关于这个的指针都会很棒!解决方法像这样更改addobserver在observeValue函数中,您可以获得两个值

  10. ios – 在Swift的UIView中找到UILabel

    我正在尝试在我的UIViewControllers的超级视图中找到我的UILabels.这是我的代码:这是在Objective-C中推荐的方式,但是在Swift中我只得到UIViews和CALayer.我肯定在提供给这个方法的视图中有UILabel.我错过了什么?我的UIViewController中的调用:解决方法使用函数式编程概念可以更轻松地实现这一目标.

返回
顶部