美文网首页iOS之功能细节iOS高质量博客自鉴
【支持iOS11】UITableView左滑删除自定义 - 实现

【支持iOS11】UITableView左滑删除自定义 - 实现

作者: pika11 | 来源:发表于2017-06-02 16:23 被阅读9260次

    写在开头:本文所介绍的方法使用的是iOS8-10中的API,不过支持在iOS11上运行。之后会写一篇介绍如何用iOS11的新API来实现,到时通知大家。(2017-08-16)


    本文介绍两种UITableView左滑菜单的实现方法,1. 默认, 2. 自定义。效果如下:

    1. 系统默认效果

    swipe-default.PNG

    2. 自定义图标效果 (类似“邮件”应用)

    swipe-customize-1.PNG

    目录:

    1. 系统默认图标实现方法
    2. 自定义图标实现方法
      a. 自定义多个左滑菜单选项
      b. 自定义左滑选项外观
        UITableView视图层级(iOS8-10, 11)
        具体实现方法 (支持iOS8-10, 11)
    3. TableCell上有其他按钮的处理方法

    1. 系统默认图标实现方法

    如果只需要使用默认图标,只需要在对应的TableViewController里实现数据源方法tableView:commitEditingStyle:forRowAtIndexPath就行了:

    - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
    {
        if (editingStyle == UITableViewCellEditingStyleDelete)
        {
            [self removeAction:indexPath.section]; // 在此处自定义删除行为
        }
        else
        {
            DEBUG_OUT(@"Unhandled editing style: %ld", (long) editingStyle);
        }
    }
    

    向左滑动table cell,该cell会自动进入编辑模式(cell.isEditing = 1),并在右边出现删除按钮,红底白字,按钮上的文字会根据系统语言自动改变;点击该按钮则触发commitEditingStyle执行相应的动作。

    如果不进行自定义,默认的左滑菜单只会有一个按钮,不过按钮上的文字可以用随意进行更改,按钮的宽度会根据文字标题长度自动调整,需要自己支持多语言:

    - (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath
    {    
        return @"想写什么都行";    
    } 
    
    效果如下: change-title.PNG

    PS:如果除了文字内容外,还想调整其它,比如文字颜色,背景颜色,选项的宽高等,则可以拿到对应的UIButton以后直接修改,具体方法参照本文2) b部分。


    2. 自定义图标实现方法

    我认为自定义又分为两个层次: a. 自定义多个左滑菜单选项b. 自定义左滑选项外观 .

    a. 自定义多个左滑菜单选项

    如果需要超过一个左滑选项,需要实现代理方法tableView:editActionsForRowAtIndexPath,在里面创建多个UITableViewRowAction:

    - (NSArray*)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(nonnull NSIndexPath *)indexPath
    {    
        // delete action
        UITableViewRowAction *deleteAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:NSLocalizedString(@"DeleteLabel", @"") handler:^(UITableViewRowAction *action, NSIndexPath *indexPath)
        {
            [tableView setEditing:NO animated:YES];  // 这句很重要,退出编辑模式,隐藏左滑菜单
            [self removeNotificationAction:index];
        }];
        
        // read action
        // 根据cell当前的状态改变选项文字
        NSInteger index = indexPath.section; 
        BOOL isRead = [[NotificationManager instance] read:index];
        NSString *readTitle = isRead ? @"Unread" : @"Read";
    
        // 创建action
        UITableViewRowAction *readAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:readTitle handler:^(UITableViewRowAction *action, NSIndexPath *indexPath) 
        {        
            [tableView setEditing:NO animated:YES];  // 这句很重要,退出编辑模式,隐藏左滑菜单
            [[NotificationManager instance] setRead:!isRead index:index];
        }];
        
        return @[deleteAction, readAction];
    }
    

    可以看到这里我们创建了delete和read两个action。这是因为实现了该方法以后,1) 中用的commitEditingStyle:forRowAtIndexPath就不会被触发了,所以删除按钮也需要自己定义。

    [tableView setEditing:NO animated:YES]; 这一行代码很重要,它的效果是在点击之后退出编辑模式,关闭左滑菜单。如果忘了加这一句的话,即使点击了按钮cell也不会还原。在1) 中使用默认模式的时候,系统会自动帮我们调用这一句,现在则需要手动调用。

    对创建并返回的每个action,apple library会自动帮我们生成一个对应按钮,配置好基本的交互,并添加到左滑菜单中。

    效果如下: two-actions-2.PNG

    上图我们对两个action都指定了UITableViewRowActionStyleNormal(灰底白字),不过其实有几种不同的预设外观 (不要问我为啥有两个都是红底白字。。。)
      UITableViewRowActionStyleNormal:灰底白字
      UITableViewRowActionStyleDefault:红底白字
      UITableViewRowActionStyleDestructive:红底白字

    我们还可以更改action button的背景色,在创建action的时候添加一行代码即可:

    deleteAction.backgroundColor = [UIColor orangeColor];
    readAction.backgroundColor = [UIColor blueColor];
    
    效果如下: change-background-2.PNG

    2b. 自定义左滑选项外观

    自定义左滑选项外观的资料很少,我做的时候找得相当辛苦。不过后来理解了UITableView的视图层级,一切就变得很简单了。

    UITableView视图层级(iOS8-10, 11)

    和iOS8-10相比,iOS11的左滑选项的视图层级有了较大改变。最显著的改变是从是UITableViewCell的子视图变成了UITableView的子视图。总结一下就是:

    iOS 8-10: UITableView -> UITableViewCell -> UITableViewCellDeleteConfirmationView -> _UITableViewCellActionButton
    iOS 11 (Xcode 8编译): UITableView -> UITableViewWrapperView -> UISwipeActionPullView -> UISwipeActionStandardButton
    iOS 11 (Xcode 9编译): UITableView -> UISwipeActionPullView -> UISwipeActionStandardButton

    不想看原理的看到这里就可以直接跳到下面去看具体的实现方法了, 有兴趣看每一层具体有些什么的同学可以继续。


    iOS8-10下的层级:

    在tableView代理方法里设置断点打印发现,正常状态下cell上只有两个subview:

    (lldb) po [tableCell subviews]
    <__NSArrayM 0x14de75670>(
    <UITableViewCellContentView: 0x14dd56940; frame = (0 0; 440 105); opaque = NO; gestureRecognizers = <NSArray: 0x14dd65ff0>; layer = <CALayer: 0x14dd56ac0>>,
    <_UITableViewCellSeparatorView: 0x14dd73810; frame = (15 154.5; 347 0.5); layer = <CALayer: 0x14dd736f0>>
    )
    

    而在左滑进入editing mode之后,就变成了3个,多出来一个 叫做UITableViewCellDeleteConfirmationView的子视图:

    (lldb) po [tableCell subviews]
    <__NSArrayM 0x14de75670>(
    <UITableViewCellDeleteConfirmationView: 0x14de737d0; frame = (375 0; 0 105); clipsToBounds = YES; autoresize = H; animations = { bounds.origin=<CASpringAnimation: 0x14db56aa0>; bounds.size=<CASpringAnimation: 0x14db5b2e0>; position=<CASpringAnimation: 0x14db498e0>; bounds.origin-2=<CASpringAnimation: 0x14db8a3d0>; bounds.size-2=<CASpringAnimation: 0x14db26c10>; }; layer = <CALayer: 0x14de72fc0>>,
    <UITableViewCellContentView: 0x14dd56940; frame = (0 0; 375 105); opaque = NO; gestureRecognizers = <NSArray: 0x14dd65ff0>; layer = <CALayer: 0x14dd56ac0>>,
    <_UITableViewCellSeparatorView: 0x14dd73810; frame = (15 154.5; 347 0.5); layer = <CALayer: 0x14dd736f0>>
    )
    

    再进一步查看这个多出来的UITableViewCellDeleteConfirmationView的子视图,发现两个UIButton:

    (lldb) po tableCell.subviews[0].subviews
    <__NSArrayM 0x14dea14c0>(
    <_UITableViewCellActionButton: 0x14de93ea0; frame = (71.5 0; 80.5 105); opaque = NO; autoresize = H; layer = <CALayer: 0x14de93150>>,
    <_UITableViewCellActionButton: 0x14de9d900; frame = (0 0; 71.5 105); opaque = NO; autoresize = H; layer = <CALayer: 0x14de9dbb0>>
    )
    

    最后再打印一下这两个UIButton的title,发现分别是“Read”和“Delete”。

    也就是说,这两个UIButton,分别对应我们在a部分创建的两个UITableViewRowAction。所以我们只要遍历UITableViewCell的子视图,拿到对应UIButton的reference,什么修改高度,添加图片,修改字体,都是手到擒来。


    iOS11下的层级 (用Xcode 8编译)

    依然在tableView代理方法里设置断点打印发现,UITableViewCell下面没有UITableViewCellDeleteConfirmationView子视图了,不过在UITableViewWrapperView下面,多了一个UISwipeActionPullView。

    (lldb) po self.tableView.subviews
    <__NSArrayM 0x1c0652cf0>(
    <UITableViewWrapperView: 0x105094200; frame = (0 0; 1000 1000); gestureRecognizers = <NSArray: 0x1c4457e50>; layer = <CALayer: 0x1c4224de0>; contentOffset: {0, 0}; contentSize: {1000, 1000}; adjustedContentInset: {0, 0, 0, 0}>,
    <UIImageView: 0x10466bb20; frame = (994.5 733; 2.5 220); alpha = 0; opaque = NO; autoresize = LM; userInteractionEnabled = NO; layer = <CALayer: 0x1c0426900>>
    )
    
    (lldb) po [self.tableView.subviews[0] subviews]
    <__NSArrayM 0x1c04457f0>(
    <UITableViewCell: 0x10e17d800; baseClass = UITableViewCell; frame = (0 277.5; 375 212.5); autoresize = W; layer = <CALayer: 0x1c0427c80>>,
    <: UITableViewCell: 0x10e165200; baseClass = UITableViewCell; frame = (0 8; 375 261.5); autoresize = W; userInteractionEnabled = NO; layer = <CALayer: 0x1c0423300>>,
    <UISwipeActionPullView: 0x10de126a0; cellEdge = UIRectEdgeRight, actions = <NSArray: 0x1c44430c0>>
    )
    

    再看一下这个UISwipeActionPullView子视图,发现了我们要找的选项按钮:

    (lldb) po subview2.subviews
    <__NSArrayM 0x1c0452ba0>(
    <UISwipeActionStandardButton: 0x14deae190; frame = (0 0; 591 104.5); opaque = NO; autoresize = W+H; tintColor = UIExtendedGrayColorSpace 1 1; layer = <CALayer: 0x1c0435860>>,
    <UISwipeActionStandardButton: 0x14debd7c0; frame = (0 0; 591 104.5); opaque = NO; autoresize = W+H; tintColor = UIExtendedGrayColorSpace 1 1; layer = <CALayer: 0x1c0621200>>
    )
    

    这两个button的title和action都和我们之前所创建的左滑选项相对应,所以我们可以用类似的方法遍历UITableView的子视图,拿到对应UIButton的reference进行修改。


    iOS11下的层级 (用Xcode 9编译)

    Xcode 9 默认使用iOS11 SDK来编译,添加打印后发现Xcode 9 编译出来的没有UITableViewWrapperView这一层,UISwipeActionPullView的子视图直接附属于UITableViewCell。

    除了少了一层UITableViewWrapperView以外,其他和Xcode 8编译出来的一样。


    放一下Xcode 8、9编译的对比图:

    xcode8.png xcode9.png

    懒人请直接看这里:p

    具体实现方法 (支持iOS8-10, 11)

    为了同时支持iOS8-10和iOS11, 我把操作选项外观的代码统一放在UITableView的ViewController的- (void)viewDidLayoutSubviews实现。

    这样做的原因有两个:

    1. 原本因为iOS8-10中,左滑选项是UITableViewCell的子视图,而在iOS11中,左滑选项变成了UITableView的子视图。虽然可以用tabelCell.superview来获取tableView,不过我认为最好从高层级去操作低层级。所以统一在UITableView层处理。
    2. iOS8-10的UITableViewCellDeleteConfirmationView子视图出现得较晚。在代理方法willBeginEditingRowAtIndexPath中还没有出现,而在viewDidLayoutSubviews则可以保证子视图出现。

    首先我们遍历UITableView的子视图拿到选项按钮(UIButton)的reference,对iOS8-10和iOS11做不同处理:

    #define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
    #define SYSTEM_VERSION_LESS_THAN(v)                 ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
    
    @property (weak, nonatomic) IBOutlet UITableView *tableView;
    @property (strong, nonatomic) NSIndexPath* editingIndexPath;  //当前左滑cell的index,在代理方法中设置
    
    - (void)viewDidLayoutSubviews
    {
        [super viewDidLayoutSubviews];
        
        if (self.editingIndexPath)
        {
            [self configSwipeButtons];
        }
    }
    

    Xcode 8 编译版本:(如果你使用的是Xcode 9,参见下面)

    - (void)configSwipeButtons
    {
        // 获取选项按钮的reference
        if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"11.0"))
        {
            // iOS 11层级 (Xcode 8编译): UITableView -> UITableViewWrapperView -> UISwipeActionPullView
            for (UIView *subview in self.tableView.subviews)
            {
                if ([subview isKindOfClass:NSClassFromString(@"UITableViewWrapperView")])
                {
                    for (UIView *subsubview in subview.subviews)
                    {
                        if ([subsubview isKindOfClass:NSClassFromString(@"UISwipeActionPullView")] && [subsubview.subviews count] >= 2)
                        {
                            // 和iOS 10的按钮顺序相反
                            UIButton *deleteButton = subsubview.subviews[1];
                            UIButton *readButton = subsubview.subviews[0];
                            
                            [self configDeleteButton:deleteButton];
                            [self configReadButton:readButton];
                        }
                    }
                }
            }
        }
        else
        {
            // iOS 8-10层级: UITableView -> UITableViewCell -> UITableViewCellDeleteConfirmationView
            NotificationCell *tableCell = [self.tableView cellForRowAtIndexPath:self.editingIndexPath];
            for (UIView *subview in tableCell.subviews)
            {
                if ([subview isKindOfClass:NSClassFromString(@"UITableViewCellDeleteConfirmationView")] && [subview.subviews count] >= 2)
                {
                    UIButton *deleteButton = subview.subviews[0];
                    UIButton *readButton = subview.subviews[1];
                    
                    [self configDeleteButton:deleteButton];
                    [self configReadButton:readButton];
                    [subview setBackgroundColor:[[ColorUtil instance] colorWithHexString:@"E5E8E8"]];
                }
            }
        }
        
        [self configDeleteButton:deleteButton];
        [self configReadButton:readButton];
    }
    

    Xcode 9 编译版本:(比Xcode 8编译出来少一层)

    - (void)configSwipeButtons
    {
        // 获取选项按钮的reference
        if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"11.0"))
        {
            // iOS 11层级 (Xcode 9编译): UITableView -> UISwipeActionPullView
            for (UIView *subview in self.tableView.subviews)
            {
                  if ([subview isKindOfClass:NSClassFromString(@"UISwipeActionPullView")] && [subview.subviews count] >= 2)
                  {
                       // 和iOS 10的按钮顺序相反
                       UIButton *deleteButton = subsubview.subviews[1];
                       UIButton *readButton = subsubview.subviews[0];
                            
                       [self configDeleteButton:deleteButton];
                       [self configReadButton:readButton];
                  }
            }
        }
        else
        {
            // iOS 8-10层级: UITableView -> UITableViewCell -> UITableViewCellDeleteConfirmationView
            NotificationCell *tableCell = [self.tableView cellForRowAtIndexPath:self.editingIndexPath];
            for (UIView *subview in tableCell.subviews)
            {
                if ([subview isKindOfClass:NSClassFromString(@"UITableViewCellDeleteConfirmationView")] && [subview.subviews count] >= 2)
                {
                    UIButton *deleteButton = subview.subviews[0];
                    UIButton *readButton = subview.subviews[1];
                    
                    [self configDeleteButton:deleteButton];
                    [self configReadButton:readButton];
                    [subview setBackgroundColor:[[ColorUtil instance] colorWithHexString:@"E5E8E8"]];
                }
            }
        }
        
        [self configDeleteButton:deleteButton];
        [self configReadButton:readButton];
    }
    

    注意一下这里我们用到了一个变量self.editingIndexPath,这代表着当前左滑的cell的index,方便我们获取iOS8-10上面的tableCell的reference。分别在控制进入和退出编辑模式的代理方法中设置的:

    - (void)tableView:(UITableView *)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath
    {
        self.editingIndexPath = indexPath;
        [self.view setNeedsLayout];   // 触发-(void)viewDidLayoutSubviews
    }
    
    - (void)tableView:(UITableView *)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath
    {
        self.editingIndexPath = nil;
    }
    

    [self.view setNeedsLayout]; 这一句非常重要,它的作用强制UITableView重新绘图。只有添加了这一句,- (void)viewDidLayoutSubviews才会被调用,才能使我们的自定义外观生效。


    好了,我们已经拿到了按钮(UIButton)的reference,然后就可以给按钮添加了图片,并且设置文本的字体和颜色了。

    - (void)configDeleteButton:(UIButton*)deleteButton
    {
        if (deleteButton)
        {
            [deleteButton.titleLabel setFont:[UIFont fontWithName:@"SFUIText-Regular" size:12.0]];
            [deleteButton setTitleColor:[[ColorUtil instance] colorWithHexString:@"D0021B"] forState:UIControlStateNormal];
            [deleteButton setImage:[UIImage imageNamed:@"Delete_icon_.png"] forState:UIControlStateNormal];
            [deleteButton setBackgroundColor:[[ColorUtil instance] colorWithHexString:@"E5E8E8"]];
            // 调整按钮上图片和文字的相对位置(该方法的实现在下面)
            [self centerImageAndTextOnButton:deleteButton]; 
        }
    }
    
    - (void)configReadButton:(UIButton*)readButton
    {
        if (readButton)
        {
            [readButton.titleLabel setFont:[UIFont fontWithName:@"SFUIText-Regular" size:12.0]];
            [readButton setTitleColor:[[ColorUtil instance] colorWithHexString:@"4A90E2"] forState:UIControlStateNormal];
            // 根据当前状态选择不同图片
            BOOL isRead = [[NotificationManager instance] read:self.editingIndexPath.row];
            UIImage *readButtonImage = [UIImage imageNamed: isRead ? @"Mark_as_unread_icon_.png" : @"Mark_as_read_icon_.png"];
            [readButton setImage:readButtonImage forState:UIControlStateNormal];
    
            [readButton setBackgroundColor:[[ColorUtil instance] colorWithHexString:@"E5E8E8"]];
            // 调整按钮上图片和文字的相对位置(该方法的实现在下面)
            [self centerImageAndTextOnButton:readButton];
        }
    }
    
    如果没有[self centerImageAndTextOnButton:readButton],则效果如下: after-layoutsubviews-1.PNG

    可以看到图标在左,文字在右,还互相重合。这就是我们熟悉的UIButton的外观处理,需要分别修改UILabel和UIImageView的frame:

    - (void)centerImageAndTextOnButton:(UIButton*)button
    {
        // this is to center the image and text on button.
        // the space between the image and text
        CGFloat spacing = 35.0;
        
        // lower the text and push it left so it appears centered below the image
        CGSize imageSize = button.imageView.image.size;
        button.titleEdgeInsets = UIEdgeInsetsMake(0.0, - imageSize.width, - (imageSize.height + spacing), 0.0);
        
        // raise the image and push it right so it appears centered above the text
        CGSize titleSize = [button.titleLabel.text sizeWithAttributes:@{NSFontAttributeName: button.titleLabel.font}];
        button.imageEdgeInsets = UIEdgeInsetsMake(-(titleSize.height + spacing), 0.0, 0.0, - titleSize.width);
        
        // increase the content height to avoid clipping
        CGFloat edgeOffset = (titleSize.height - imageSize.height) / 2.0;
        button.contentEdgeInsets = UIEdgeInsetsMake(edgeOffset, 0.0, edgeOffset, 0.0);
        
        // move whole button down, apple placed the button too high in iOS 10
        if (SYSTEM_VERSION_LESS_THAN(@"11.0"))
        {
            CGRect btnFrame = button.frame;
            btnFrame.origin.y = 18;
            button.frame = btnFrame;
        }
    }
    
    调整过后就可以做到文章开头展示的效果了: swipe-customize-2.PNG

    PS:假如仅支持iOS8-10的话,我个人是倾向于创建一个custom class,继承UITableViewCell,然后在该custom class中-(void)layoutSubviews来实现的。那样代码更干净,不需要特意去调用[self.view setNeedsLayout]; 不过为了支持新版本总是要有所牺牲的。


    3. TableCell上有其它按钮的处理方法

    我自己做的时候遇到了一种特殊情况,UITableViewCell上面带有比较显著的button,类似下图的这种情况: swipe-button-1.PNG

    这种情况比较尴尬的就是当你左滑的时候如果刚好碰到了YES或者NO button, 在进入左滑选项的同时会触发按钮选项,相当容易引发误操作。为了解决这个问题,我在TableViewController中实现了下面两个代理方法:

    - (void)tableView:(UITableView *)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath
    {
        UITableViewCell *tableCell = [tableView cellForRowAtIndexPath:indexPath];
        // disable button touch event during swipe
        for (UIView *view in [tableCell.contentView subviews])
        {
            if ([view isKindOfClass:[UIButton class]]) {
                [view setUserInteractionEnabled:NO];
            }
        }
    }
    
    - (void)tableView:(UITableView *)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath
    {
        UITableViewCell *tableCell = [tableView cellForRowAtIndexPath:indexPath];
        for (UIView *view in [tableCell.contentView subviews])
        {
            if ([view isKindOfClass:[UIButton class]]) {
                [view setUserInteractionEnabled:YES];
            }
        }
    }
    

    tableView:willBeginEditingRowAtIndexPath是在cell进入editing mode之前调用的,在这里将contentView下面的所有按钮的交互设置为disabled。
    tableView:didEndEditingRowAtIndexPath是在cell即将退出editing mode时调用的,在这里将之前被disable的所有button的交互重新设置为enabled。

    这样就可以保证在左滑菜单出现的时候,原本cell上的那些按钮都处于不能点按的状态,也就不会触发误操作了。

    PS: 试过直接disable 整个contentView不起作用,必须直接disable对应的UIButton才行,推测跟apple自己处理event的有限次序有关。

    <最后更新时间:2017-09-11>

    相关文章

      网友评论

      • iOS_:左滑删除cell 为什么会越出父视图 11系统以上
      • 6b8eb971715a:大神,现在button避免重复点击用了runtime ,https://blog.csdn.net/icetime17/article/details/51782983 这个,然后button删除按钮点击无反应了
      • hylanApple:温馨提示:我目前是swift4.1,现在层级又变了,自己po一下,改下方法可以了
      • koreadragon:我连文字都看不见
      • 法拉达:调节图片和文字,图片始终动不了
      • 沐玉清风:同问:如果按钮只设置图片没有文字,怎么自定义每个按钮的宽度呢
        沐玉清风:我这边左滑删除也添加的有二次确认删除,不会影响farme的修改
        ,MGSwipeButton里面的方法很丰富
        沐玉清风:如果按钮只设置图片没有文字,更改按钮间隔
        采用:MGSwipeButton *button = [MGSwipeButton buttonWithTitle:@"" icon:icons[i] backgroundColor:PNCloudWhite insets:insets];
        笨笨编程:同问:现在我的方案是在 layoutsubviews 中找到这个按钮,通过修改按钮父视图 frame,然后再修改按钮 frame,但是我的问题是,需要点击删除之后有二次确认删除,那个 frame 在修改有问题。希望加QQ 和你详聊:2638006336,非常感谢。
      • Jabir_Zhang:楼主您好,除了左滑,我在cell里有一个按钮点了以后能否手动调cell左滑?
      • 滚滚猫:iOS 11之后,侧滑删除的红色删除块并不会根据titleForDeleteConfirmationButtonForRowAtIndexPath方法返回的String加长变宽,请问有什么解决方法吗,整了一天也没找到。
        1cdb19c230be:@滚滚猫 猫猫 其实不用这么麻烦的 直接用MGSwipeTableCell 几句代码就可以了
        滚滚猫:@superWWWWWWW 没找到,改用手势自定义做了
        1cdb19c230be:你好 你找到解决办法了吗?
      • waekessi:真大神
      • 不要动:[NotificationManager instance] 这个是你一个类吗
      • Nbm:不错,解决了我的问题
      • 7a946bf5d2ca:我遇到了一个问题 在iOS11系统下 按钮的位置跑偏了 Y值向下移动了大概40像素 找了很久找不到原因
      • 菁欣陌陌:请问怎么设置文字和图片左右水平居中对齐排布呀?你的是上下排布
        夏夜晚风:兄dei,按钮默认就是 图文左右水平对其呀
      • Zac波:我自己的方法没有这么复杂。。。
        在XIB里直接把自定义按钮画在cell的右侧,给一个约束,这样在拖动cell的时候,右侧的按钮会被一并拖过来。。。(需要给UITableViewRowAction的backgroundColor设置透明就行)
        iOS11虽然UITableViewRowAction的层级有所改变,但思路并没有变,不过backgroundColor不能给clear,需要给UIColor(red: 0, green: 0, blue: 0, alpha: 0)。另外cell和cell的contentView的clipToBounds需要关掉,否则任何画在cell之外的view都会被裁切掉。
      • 凯文Kevin21:正好用到了,,:+1: 我改好了iOS8.0 到iOS10的, 到iOS11上面发现还是原来系统左滑删除。
        笨笨编程:你好,这个侧滑删除的红色删除块 怎么修改它的宽度哈。你这边有方案不,感谢QQ详聊2638006336
      • 瓜而不皮很灵性:只有一个按钮的时候,左滑可以滑动很远是什么情况?记得之前是滑不了多远的,并且左滑幅度大的时候底部还会有红色背景出现,请解答一下,谢谢
        笨笨编程:这个是iOS11新特性,可以设置参数禁掉的。不过我这边有个问题,这个侧滑删除的红色删除块 怎么修改它的宽度哈。你这边有方案不,感谢QQ详聊2638006336
      • 瓜而不皮很灵性:请教一下,按钮上面图片和lable大小怎么调整
        笨笨编程:你这边有解决方案了么,我不知道怎么修改它们的frame啊 感谢QQ详聊 2638006336
      • b9ea49a52af5:如果按钮只设置图片没有文字,怎么自定义每个按钮的宽度呢
      • 风说十里无她:如何修改向左滑动距离呢
        笨笨编程:同问:现在我的方案是在 layoutsubviews 中找到这个按钮,通过修改按钮父视图 frame,然后再修改按钮 frame,但是我的问题是,需要点击删除之后有二次确认删除,那个 frame 在修改有问题。希望加QQ 和你详聊:2638006336,非常感谢。
      • 960b0a0481df:还有,自定义的可以改变按钮的宽度吗?
        笨笨编程:同问:现在我的方案是在 layoutsubviews 中找到这个按钮,通过修改按钮父视图 frame,然后再修改按钮 frame,但是我的问题是,需要点击删除之后有二次确认删除,那个 frame 在修改有问题。希望加QQ 和你详聊:2638006336,非常感谢。
      • 风说十里无她:如果只有一个按钮, 而我想要设置向左滑动的距离(也就是将这个左滑显示区域变宽), 应该操作哪里呢???? 拜托了
        笨笨编程:同问:现在我的方案是在 layoutsubviews 中找到这个按钮,通过修改按钮父视图 frame,然后再修改按钮 frame,但是我的问题是,需要点击删除之后有二次确认删除,那个 frame 在修改有问题。希望加QQ 和你详聊:2638006336,非常感谢。
      • luochuanAD:https://github.com/LuochuanAD/OC-LCTableViewCell 适配了iOS11
        瓜而不皮很灵性:@luochuanAD 你这个demo左滑了之后,回不去,你有遇到一个按钮的时候左滑幅度很大这个问题吗?
        当地比较英俊的男子:如果我是用UItablelView写的,在UIviewController上的- (void)viewDidLayoutSubviews如何写?
        luochuanAD:这是自定义左划按钮的demo
      • d4999f3d52df:哇,谢谢分享,刚好现在也遇到这个问题了
      • e094488ed710:你好问一下 有时候 侧滑 触发这个方法的时候configSwipeButtons ,里面的方法是没有效果,显示的是系统的红色背景
        pika11:请问有时没有效果是什么意思?configSwipeButtons放在viewDidLayoutSubviews下面了吗?
      • David_Do:这个遍历方法有点蛋疼啊, 看看有没有一种简单点的方法处理 :joy:
        笨笨编程:@pika11 就算遍历能解决我的问题也可以啊,怎么动态修改按钮的frame和按钮父视图的frame呢
        pika11:我翻遍了网上的帖子,唯一成功地就是这个蛋疼的遍历方法:joy:
      • 当地比较英俊的男子:有没有写过按钮竖排的,我发现左滑出来后点击按钮会出现红色背景
        小丑_3bd1:大神实现竖排的了没,求指教呀:fearful:
        当地比较英俊的男子:@pika11 你试一下自定义三个按钮竖排的,看看能不能再ios11下捕捉到这三个按钮的点击,等你指导呢
        pika11:我也有遇到在ios11下面点击会出现灰色背景的问题,但是因为一点击左滑按钮就收起来了,影响不大我就没有管
      • Mhhhhhhy:感谢大神分享
      • 12af29900d36:楼主你好,ipad 是8.1.1的 结果不执行- (NSArray*)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(nonnull NSIndexPath *)indexPath
        这个代理方法怎么办呢
        pika11:你有在ViewControlller的interface里加入UITableViewDelegate吗?如果不加的话,所有代理方法都不会被触发
        @interface NotificationViewController<UITableViewDataSource, UITableViewDelegate>
      • 68dd45755f11:编辑模式下,点击左侧的红底白横线按钮,滑出的删除按钮是文字,不是图片,有什么办法解决吗
        pika11:如果要加图片,参照章节2. 自定义图标实现方法下面的b. 自定义左滑选项外观。
      • 68dd45755f11:楼主,请教个问题哈,按照上面的步骤,编辑模式下,点击左侧的红底横线删除按钮,右侧出现的按钮只有dele
        -(NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath {
        return @"dele";
        },没有图片,有没有什么办法解决吗,谢谢
        pika11:你用的这个api是改文字的,并不能添加图片。如果要加图片,参照章节2. 自定义图标实现方法下面的b. 自定义左滑选项外观。
      • ebay_Happy:感谢大神,11出了很多问题
      • 莫云溪:感谢博主分享!请教一个问题,我重写了tableView:editActionsForRowAtIndexPath:自定义侧滑按钮,如果我把侧滑按钮滑出来,这时候调用reloadData,侧滑按钮就自动消失了。有没有什么办法在reloadData之后又把这个侧滑按钮显示出来呢?
        pika11:我觉得既然都reloadData了,那么侧滑按钮自动消失也很正常。如果你一定要保留,可以考虑认为设置你想要的cell的self.isEditing为true试一下,table view是靠这个来判断是不是处于编辑模式的,设置完之后记得setNeedsLayout来刷新视图。
      • 904dc3c02374:666,感谢大神,正遇到ios11的问题呢
        这个熊孩子不太冷:@pika11 设置UIButton.textLabel.text是啥意思
        pika11:@StephenYang78 如果是文字调整不了,有可能你设置的是整个button的title,那就不能调整。要设置UIButton.textLabel.text才可以调节。图片不能调整有可能是在iOS11上没有拿到正确的按钮reference,检查一下iOS11的层级遍历是否正确。
        904dc3c02374: 调整图片和文字位置大小时,为什么我在ios10上面可以调整图片,文字调整不了。但是在ios11上连图片也调整不了了
      • Tangmi_Up:楼主写得很详尽,但个人认为在最后调整图片和文字位置的时候强行改变button的y值有点不妥
        pika11:你说得对,但是强迫症表示接受不了button不居中:mask: 还好iOS11已经自动居中了。
      • Comic_8c68:楼主有没有遇到过,左滑出去后,很难滑回来的情况,操作当前 的 UITableViewCell
        Comic_8c68:@pika11 以前是手放在上面滑回去,现在如果滑的话,是滑不动的,看来苹果改变了交互方式
        pika11:没有呢,随意点cell的任意地方就退出了左滑模式呢
      • 33a02bf71691:有出现 左划的幅度比较大的情况下 会默认执行第一个按钮的事件么。我得是这样。
        Remover:@重复昵称 请问默认执行事件的问题 有解决吗,怎么关闭默认执行?
        33a02bf71691:@pika11 怎么关闭呢?
        pika11:本文中写的实现方法用iOS10 SDK编译不会。试过IOS11的新出的swipe action似乎是会默认执行,但是是可以关闭这个默认执行的行为的。
      • 131c3f7a8064:我在Xcode9下编译iOS9.3.2 为什么有UITableViewWrapperView这一层呢
        pika11:我只能说有没有这一层完全是apple的SDK控制的,如果有那也没有办法,就要由你自己在代码里面进行适配支持了。支持多个version从来都是很痛苦的。
      • 去你的联盟:我再调节图片和文字的位置的时候,图片我可以调节位置,发现label上面的文字怎么也调节不了
        这个熊孩子不太冷:@去你的联盟 你好在ios11以下有这问题,改变不了title位置,怎么解决
        去你的联盟:@pika11 谢谢,确实是这个问题
        pika11:有可能你设置的是整个button的title,那就不能调整。要设置UIButton.textLabel.text才可以调节。这是一个我也踩过的坑。。。
      • 1cdb19c230be:你好 在11里 你这句判断 错了吧 根本进不去 if ([subview isKindOfClass:NSClassFromString(@"UITableViewWrapperView")])

        1cdb19c230be:你好 。 在xcode9编译 发现有两个UISwipeActionPullView 那我们到底要取哪个呢
        pika11:已经添加了Xcode 9编译版本的代码,你再试一下。多谢指出。
        pika11:判断条件应该是没有错的。有一种可能,你是不是用的xcode 9编译的?我发现在Xcode 9 编译下, UITableViewWrapperView这一层是不存在的。Xcode 8 下编译才有。
      • 8b9b696c1a08:有swift的代码吗?我看oc有点吃力:cold_sweat:
        867f3b117741:哥们没学过OC?
        ebay_Happy:牛逼
        pika11:不好意思呢,没有swift版本。
      • 茗荚小草:哇 感谢分享 ~正好遇到了这个问题
        pika11:@雪山飞狐_91ae 因为是由公司项目开发里的代码片段修改来的,所以可能没有demo可以帮到你,不过有问题可以发信息问我。
        雪山飞狐_91ae:有demo可以学习一下吗
        pika11:@茗荚小草 开心~

      本文标题:【支持iOS11】UITableView左滑删除自定义 - 实现

      本文链接:https://www.haomeiwen.com/subject/sdcsattx.html