【支持iOS11】UITableView左滑刪除自定義 - 實(shí)現(xiàn)多選項(xiàng)并使用自定義圖片

寫在開頭:本文所介紹的方法使用的是iOS8-10中的API盐肃,不過同樣支持在iOS11上運(yùn)行骡显。
<最近更新時(shí)間:2017-09-11>


目錄:

  1. 效果展示
  2. 系統(tǒng)默認(rèn)左滑菜單實(shí)現(xiàn)
  3. 自定義多個(gè)左滑菜單選項(xiàng)
  4. 自定義左滑菜單選項(xiàng)圖標(biāo)
    4.1 實(shí)現(xiàn)方法 (支持iOS8-10, 11)
    4.2 實(shí)現(xiàn)原理:UITableView視圖層級(jí)(iOS8-10, 11)
  5. TableCell上有其他按鈕的處理方法

1. 效果展示

本文介紹兩種UITableView左滑菜單的實(shí)現(xiàn)方法米酬,效果如下:

系統(tǒng)默認(rèn)效果

swipe-default.PNG

自定義圖標(biāo)效果 (類似“郵件”應(yīng)用)

swipe-customize-1.PNG


2. 系統(tǒng)默認(rèn)左滑菜單實(shí)現(xiàn)

如果只需要使用默認(rèn)圖標(biāo)飞盆,只需要在對(duì)應(yīng)的TableViewController里實(shí)現(xiàn)數(shù)據(jù)源方法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);
    }
}

向左滑動(dòng)table cell析命,該cell會(huì)自動(dòng)進(jìn)入編輯模式(cell.isEditing = 1)备典,并在右邊出現(xiàn)刪除按鈕喜每,紅底白字务唐,按鈕上的文字會(huì)根據(jù)系統(tǒng)語言自動(dòng)改變雳攘;點(diǎn)擊該按鈕則觸發(fā)commitEditingStyle執(zhí)行相應(yīng)的動(dòng)作。

如果不進(jìn)行自定義,默認(rèn)的左滑菜單只會(huì)有一個(gè)按鈕,不過按鈕上的文字可以用隨意進(jìn)行更改系馆,按鈕的寬度會(huì)根據(jù)文字標(biāo)題長(zhǎng)度自動(dòng)調(diào)整,需要自己支持多語言:

- (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath
{    
    return @"想寫什么都行";    
} 

效果如下:
change-title.PNG

PS:如果除了文字內(nèi)容外喧兄,還想調(diào)整其它,比如文字顏色啊楚,背景顏色吠冤,選項(xiàng)的寬高等,則可以拿到對(duì)應(yīng)的UIButton以后直接修改恭理,具體方法參照本文2) b部分拯辙。


3. 自定義多個(gè)左滑菜單選項(xiàng)

如果需要超過一個(gè)左滑選項(xiàng),需要實(shí)現(xiàn)代理方法tableView:editActionsForRowAtIndexPath颜价,在里面創(chuàng)建多個(gè)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
    // 根據(jù)cell當(dāng)前的狀態(tài)改變選項(xiàng)文字
    NSInteger index = indexPath.section; 
    BOOL isRead = [[NotificationManager instance] read:index];
    NSString *readTitle = isRead ? @"Unread" : @"Read";

    // 創(chuàng)建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];
}

可以看到這里我們創(chuàng)建了delete和read兩個(gè)action。這是因?yàn)閷?shí)現(xiàn)了該方法以后专挪,1) 中用的commitEditingStyle:forRowAtIndexPath就不會(huì)被觸發(fā)了及志,所以刪除按鈕也需要自己定義。

[tableView setEditing:NO animated:YES]; 這一行代碼很重要寨腔,它的效果是在點(diǎn)擊之后退出編輯模式速侈,關(guān)閉左滑菜單。如果忘了加這一句的話迫卢,即使點(diǎn)擊了按鈕cell也不會(huì)還原锌畸。在1) 中使用默認(rèn)模式的時(shí)候,系統(tǒng)會(huì)自動(dòng)幫我們調(diào)用這一句靖避,現(xiàn)在則需要手動(dòng)調(diào)用。

對(duì)創(chuàng)建并返回的每個(gè)action比默,apple library會(huì)自動(dòng)幫我們生成一個(gè)對(duì)應(yīng)按鈕幻捏,配置好基本的交互,并添加到左滑菜單中命咐。

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

上圖我們對(duì)兩個(gè)action都指定了UITableViewRowActionStyleNormal(灰底白字)篡九,不過其實(shí)有幾種不同的預(yù)設(shè)外觀 (不要問我為啥有兩個(gè)都是紅底白字。醋奠。榛臼。)
? UITableViewRowActionStyleNormal:灰底白字
? UITableViewRowActionStyleDefault:紅底白字
? UITableViewRowActionStyleDestructive:紅底白字

我們還可以更改action button的背景色伊佃,在創(chuàng)建action的時(shí)候添加一行代碼即可:

deleteAction.backgroundColor = [UIColor orangeColor];
readAction.backgroundColor = [UIColor blueColor];

效果如下:
change-background-2.PNG



4. 自定義左滑菜單選項(xiàng)外觀

自定義左滑選項(xiàng)外觀的資料很少,我做的時(shí)候找得相當(dāng)辛苦沛善。不過后來理解了UITableView的視圖層級(jí)航揉,一切就變得很簡(jiǎn)單了。先放實(shí)現(xiàn)方法金刁,再放原理解釋帅涂。

4.1 實(shí)現(xiàn)方法 (支持iOS8-10, 11)

為了同時(shí)支持iOS8-10和iOS11, 我把操作選項(xiàng)外觀的代碼統(tǒng)一放在UITableView的ViewController的- (void)viewDidLayoutSubviews實(shí)現(xiàn)。

這樣做的原因有兩個(gè):

  1. 原本因?yàn)閕OS8-10中尤蛮,左滑選項(xiàng)是UITableViewCell的子視圖媳友,而在iOS11中,左滑選項(xiàng)變成了UITableView的子視圖产捞。雖然可以用tabelCell.superview來獲取tableView醇锚,不過我認(rèn)為最好從高層級(jí)去操作低層級(jí)。所以統(tǒng)一在UITableView層處理坯临。
  2. iOS8-10的UITableViewCellDeleteConfirmationView子視圖出現(xiàn)得較晚焊唬。在代理方法willBeginEditingRowAtIndexPath中還沒有出現(xiàn),而在viewDidLayoutSubviews則可以保證子視圖出現(xiàn)尿扯。

首先我們遍歷UITableView的子視圖拿到選項(xiàng)按鈕(UIButton)的reference求晶,對(duì)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;  //當(dāng)前左滑cell的index,在代理方法中設(shè)置

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    
    if (self.editingIndexPath)
    {
        [self configSwipeButtons];
    }
}

Xcode 8 編譯版本:(如果你使用的是Xcode 9衷笋,參見下面)

- (void)configSwipeButtons
{
    // 獲取選項(xiàng)按鈕的reference
    if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"11.0"))
    {
        // iOS 11層級(jí) (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層級(jí): 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
{
    // 獲取選項(xiàng)按鈕的reference
    if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"11.0"))
    {
        // iOS 11層級(jí) (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層級(jí): 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];
}

注意一下這里我們用到了一個(gè)變量self.editingIndexPath芳杏,這代表著當(dāng)前左滑的cell的index,方便我們獲取iOS8-10上面的tableCell的reference辟宗。分別在控制進(jìn)入和退出編輯模式的代理方法中設(shè)置的:

- (void)tableView:(UITableView *)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath
{
    self.editingIndexPath = indexPath;
    [self.view setNeedsLayout];   // 觸發(fā)-(void)viewDidLayoutSubviews
}

- (void)tableView:(UITableView *)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath
{
    self.editingIndexPath = nil;
}

[self.view setNeedsLayout]; 這一句非常重要爵赵,它的作用強(qiáng)制UITableView重新繪圖。只有添加了這一句泊脐,- (void)viewDidLayoutSubviews才會(huì)被調(diào)用空幻,才能使我們的自定義外觀生效。


好了容客,我們已經(jīng)拿到了按鈕(UIButton)的reference秕铛,然后就可以給按鈕添加了圖片,并且設(shè)置文本的字體和顏色了缩挑。

- (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"]];
        // 調(diào)整按鈕上圖片和文字的相對(duì)位置(該方法的實(shí)現(xiàn)在下面)
        [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];
        // 根據(jù)當(dāng)前狀態(tài)選擇不同圖片
        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"]];
        // 調(diào)整按鈕上圖片和文字的相對(duì)位置(該方法的實(shí)現(xiàn)在下面)
        [self centerImageAndTextOnButton:readButton];
    }
}

如果沒有[self centerImageAndTextOnButton:readButton]但两,則效果如下:
after-layoutsubviews-1.PNG

可以看到圖標(biāo)在左,文字在右供置,還互相重合谨湘。這就是我們熟悉的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;
    }
}

調(diào)整過后就可以做到文章開頭展示的效果了:
swipe-customize-2.PNG

PS:假如僅支持iOS8-10的話,我個(gè)人是傾向于創(chuàng)建一個(gè)custom class紧阔,繼承UITableViewCell坊罢,然后在該custom class中-(void)layoutSubviews來實(shí)現(xiàn)的。那樣代碼更干凈擅耽,不需要特意去調(diào)用[self.view setNeedsLayout]; 不過為了支持新版本總是要有所犧牲的活孩。


4.2 實(shí)現(xiàn)原理:UITableView視圖層級(jí)(iOS8-10, 11)

不想看原理可以跳過這部分。

和iOS8-10相比秫筏,iOS11的左滑選項(xiàng)的視圖層級(jí)有了較大改變诱鞠。最顯著的改變是從是UITableViewCell的子視圖變成了UITableView的子視圖≌饩矗總結(jié)一下就是:

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

--

iOS8-10下的層級(jí):

在tableView代理方法里設(shè)置斷點(diǎn)打印發(fā)現(xiàn)航夺,正常狀態(tài)下cell上只有兩個(gè)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>>
)

而在左滑進(jìn)入editing mode之后,就變成了3個(gè)崔涂,多出來一個(gè) 叫做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>>
)

再進(jìn)一步查看這個(gè)多出來的UITableViewCellDeleteConfirmationView的子視圖阳掐,發(fā)現(xiàn)兩個(gè)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>>
)

最后再打印一下這兩個(gè)UIButton的title,發(fā)現(xiàn)分別是“Read”和“Delete”冷蚂。

也就是說缭保,這兩個(gè)UIButton,分別對(duì)應(yīng)我們?cè)赼部分創(chuàng)建的兩個(gè)UITableViewRowAction蝙茶。所以我們只要遍歷UITableViewCell的子視圖艺骂,拿到對(duì)應(yīng)UIButton的reference,什么修改高度隆夯,添加圖片钳恕,修改字體,都是手到擒來蹄衷。

--

iOS11下的層級(jí) (用Xcode 8編譯)

依然在tableView代理方法里設(shè)置斷點(diǎn)打印發(fā)現(xiàn)忧额,UITableViewCell下面沒有UITableViewCellDeleteConfirmationView子視圖了,不過在UITableViewWrapperView下面愧口,多了一個(gè)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>>
)

再看一下這個(gè)UISwipeActionPullView子視圖,發(fā)現(xiàn)了我們要找的選項(xiàng)按鈕:

(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>>
)

這兩個(gè)button的title和action都和我們之前所創(chuàng)建的左滑選項(xiàng)相對(duì)應(yīng)耍属,所以我們可以用類似的方法遍歷UITableView的子視圖托嚣,拿到對(duì)應(yīng)UIButton的reference進(jìn)行修改。

--

iOS11下的層級(jí) (用Xcode 9編譯)

Xcode 9 默認(rèn)使用iOS11 SDK來編譯厚骗,添加打印后發(fā)現(xiàn)Xcode 9 編譯出來的沒有UITableViewWrapperView這一層注益,UISwipeActionPullView的子視圖直接附屬于UITableViewCell。

除了少了一層UITableViewWrapperView以外溯捆,其他和Xcode 8編譯出來的一樣。

放一下Xcode 8、9編譯的對(duì)比圖:

xcode8.png
xcode9.png



5. TableCell上有其它按鈕的處理方法

我自己做的時(shí)候遇到了一種特殊情況提揍,UITableViewCell上面帶有比較顯著的button啤月,類似下圖的這種情況:
swipe-button-1.PNG

這種情況比較尷尬的就是當(dāng)你左滑的時(shí)候如果剛好碰到了YES或者NO button, 在進(jìn)入左滑選項(xiàng)的同時(shí)會(huì)觸發(fā)按鈕選項(xiàng),相當(dāng)容易引發(fā)誤操作劳跃。為了解決這個(gè)問題谎仲,我在TableViewController中實(shí)現(xiàn)了下面兩個(gè)代理方法:

- (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進(jìn)入editing mode之前調(diào)用的,在這里將contentView下面的所有按鈕的交互設(shè)置為disabled刨仑。
tableView:didEndEditingRowAtIndexPath是在cell即將退出editing mode時(shí)調(diào)用的郑诺,在這里將之前被disable的所有button的交互重新設(shè)置為enabled。

這樣就可以保證在左滑菜單出現(xiàn)的時(shí)候杉武,原本cell上的那些按鈕都處于不能點(diǎn)按的狀態(tài)辙诞,也就不會(huì)觸發(fā)誤操作了。

PS: 試過直接disable 整個(gè)contentView不起作用轻抱,必須直接disable對(duì)應(yīng)的UIButton才行飞涂,推測(cè)跟apple自己處理event的有限次序有關(guān)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末祈搜,一起剝皮案震驚了整個(gè)濱河市较店,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌容燕,老刑警劉巖梁呈,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異蘸秘,居然都是意外死亡官卡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門秘血,熙熙樓的掌柜王于貴愁眉苦臉地迎上來味抖,“玉大人,你說我怎么就攤上這事灰粮∽猩” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵粘舟,是天一觀的道長(zhǎng)熔脂。 經(jīng)常有香客問我,道長(zhǎng)柑肴,這世上最難降的妖魔是什么霞揉? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮晰骑,結(jié)果婚禮上适秩,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好秽荞,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布骤公。 她就那樣靜靜地躺著,像睡著了一般扬跋。 火紅的嫁衣襯著肌膚如雪阶捆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天钦听,我揣著相機(jī)與錄音洒试,去河邊找鬼。 笑死朴上,一個(gè)胖子當(dāng)著我的面吹牛垒棋,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播余指,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼捕犬,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了酵镜?” 一聲冷哼從身側(cè)響起碉碉,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎淮韭,沒想到半個(gè)月后垢粮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡靠粪,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年蜡吧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片占键。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡昔善,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出畔乙,到底是詐尸還是另有隱情君仆,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布牲距,位于F島的核電站返咱,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏牍鞠。R本人自食惡果不足惜咖摹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望难述。 院中可真熱鬧萤晴,春花似錦吐句、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至两入,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間敲才,已是汗流浹背裹纳。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留紧武,地道東北人剃氧。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像阻星,于是被迫代替她去往敵國(guó)和親朋鞍。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 之前寫過一篇UITableView定制自定義cell左滑刪除按鈕小竅門,當(dāng)時(shí)電腦未升級(jí)xcode還沒有升級(jí)妥箕,所以當(dāng)...
    flowerflower閱讀 7,590評(píng)論 16 9
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)滥酥、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,105評(píng)論 4 62
  • 人會(huì)長(zhǎng)大三次畦幢。第一次是在發(fā)現(xiàn)自己不是世界中心的時(shí)候坎吻。第二次是在發(fā)現(xiàn)即使再怎么努力,終究還是有些事令人無能為力的時(shí)候...
    又一個(gè)小太陽(yáng)閱讀 194評(píng)論 2 0
  • 或許沒有結(jié)局的結(jié)尾才讓人刻骨銘心∮畲校現(xiàn)在他跟另一個(gè)女孩在一起瘦真,而我也在期待屬于我的一輩子。曾經(jīng)覺得除了他不會(huì)有人會(huì)讓...
    錵錵閱讀 409評(píng)論 0 1
  • 熱氣球黍瞧,帝王谷诸尽,哈特謝普蘇特神廟,卡納克神廟印颤,門農(nóng)巨像您机。 人生中的第一次熱氣球,雖然降落不算浪漫但經(jīng)歷真的美好膀哲。然...
    喬喬喬木閱讀 175評(píng)論 0 1