該文同時(shí)發(fā)表在騰訊WeTest公眾號(hào):iOS UITableView左滑操作功能的實(shí)現(xiàn)(iOS8-11) 歡迎點(diǎn)擊閱讀
本文主要是介紹下iOS 11系統(tǒng)及iOS 11之前的系統(tǒng)在實(shí)現(xiàn)左滑操作功能上的區(qū)別,及如何自定義左滑的標(biāo)題顏色、字體
1似扔、左滑操作功能實(shí)現(xiàn)
1.1 如果左滑的時(shí)候只有一個(gè)操作按鈕懂扼,可以使用如下三個(gè)delegate方法來(lái)實(shí)現(xiàn):
//editing style
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewCellEditingStyleDelete;
}
//設(shè)置滑動(dòng)cell出現(xiàn)的button標(biāo)題揍移,默認(rèn)是"delete"
- (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath {
return @"刪除";//or @"置頂"
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
//點(diǎn)擊按鈕后的操作
}
1.2 如果左滑有一個(gè)或多個(gè)操作按鈕绎秒,iOS8-10 可使用如下兩個(gè)delegate方法:
//如果tableView中的每一行都可以進(jìn)行左滑操作搔涝,該方法可不實(shí)現(xiàn)
//If not implemented, all editable cells will have UITableViewCellEditingStyleDelete
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == FMMineCollectionSection_AlbumItems) {
return UITableViewCellEditingStyleDelete;
}
return UITableViewCellEditingStyleNone;
}
// 必須寫的方法(否則iOS 8無(wú)法刪除黍图,iOS 9及其以上不寫沒(méi)問(wèn)題)曾雕,和editActionsForRowAtIndexPath配對(duì)使用,里面什么不寫也行
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
}
//從iOS11開始該方法被廢棄
- (NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewRowAction *topRowAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:@"置頂" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
//操作按鈕點(diǎn)擊的操作
}];
topRowAction.backgroundColor = KE_COLOR(@"BT3");
topRowAction.title = @"置頂";
UITableViewRowAction *deleteRowAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"刪除" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
NSLog(@"點(diǎn)擊了刪除");
}];
return @[topRowAction, deleteRowAction];
}
}
1.3 iOS 11之后助被,tableView的delegate增加了兩個(gè)方法剖张,用來(lái)取代editActionsForRowAtIndexPath方法,如下:
// Swipe actions
// These methods supersede -editActionsForRowAtIndexPath: if implemented
// return nil to get the default swipe actions
- ( UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath {
UIContextualAction *topRowAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleNormal title:@"置頂" handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
NSLog(@"點(diǎn)擊了置頂");
}];
UIContextualAction *deleteRowAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive title:@"delete" handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
NSLog(@"點(diǎn)擊了刪除");
}];
UISwipeActionsConfiguration *config = [UISwipeActionsConfiguration configurationWithActions:@[topRowAction,deleteRowAction]];
return config;
}
在1.2和1.3中揩环,如果是需要適配iOS 11之前的版本搔弄,以上三個(gè)方法都需要實(shí)現(xiàn)。
1.4 上面1.2和1.3中實(shí)現(xiàn)的方法的區(qū)別
體驗(yàn)上的不同就是當(dāng)左滑只有一個(gè)button時(shí)丰滑,iOS 11中可以一直左滑顾犹,滑到一定程度時(shí),會(huì)執(zhí)行點(diǎn)擊按鈕的操作褒墨,iOS 11之前的不會(huì)炫刷。
iOS 11之前如果想增大button區(qū)域,可通過(guò)在標(biāo)題前后加空格的方式貌亭,但iOS 11不行柬唯,加空格無(wú)效,button大小固定圃庭,超過(guò)4個(gè)字時(shí)換行顯示锄奢。
2圃郊、左滑操作自定義標(biāo)題顏色蔬咬、字體
因?yàn)橄到y(tǒng)對(duì)左滑出的按鈕只提供了3個(gè)可設(shè)置的屬性:title、backgroundColor甸怕、image书在,如果使用自定義的titleColor和font灰伟,就需要自己來(lái)實(shí)現(xiàn)了。實(shí)現(xiàn)的思想是hook系統(tǒng)實(shí)現(xiàn),但鑒于UITableView的view層級(jí)結(jié)構(gòu)在iOS 11中有所改變栏账,所以iOS8-10和iOS11的實(shí)現(xiàn)有所不同帖族,以下分別給出。
考慮到代碼的可復(fù)用性挡爵,自定義左滑操作的字體大小和顏色的代碼不寫在viewController中竖般,而是寫在UITableView
和UITableViewCell
的Category
中,對(duì)外提供editActionTitleColor
和editActionTitleFont
屬性來(lái)設(shè)置顏色和大小茶鹃,需要使用自定義顏色和字體時(shí)只需要設(shè)置一下這兩個(gè)屬性即可涣雕。
2.1 iOS 8-10 設(shè)置標(biāo)題顏色和字體
左滑操作后,UITableView
的層級(jí)結(jié)構(gòu)如下圖:
由上圖可知闭翩,左滑的操作按鈕是在UITableViewCell
的子view挣郭,所以我們可以在UITableViewCell
的category
中hook掉layoutSubviews
方法,找到UITableViewCellDeleteConfirmationView
的子view button疗韵,設(shè)置字體顏色和大小兑障。
代碼如下:
- (void)applyEditActionButtonStyle
{
if (self.editActionTitleColor) {//設(shè)置editActionTitleFont同理
UIButton *btn = [self __findSwipActionButton];
[btn setTitleColor:self.editActionTitleColor forState:UIControlStateNormal];
}
}
- (UIButton *)__findSwipActionButton{
if (![Common iOS11]) {
UIView *extView = (UIView *)[self findSubviewOfTest:@"UITableViewCellDeleteConfirmationView" resursion:YES];
for (UIButton *btn in extView.subviews) {
if ([btn isKindOfClass:[UIButton class]]) {
return btn;
}
}
}
return nil;
}
2.2 iOS 11 設(shè)置標(biāo)題顏色和字體
左滑操作后,UITableView的層級(jí)結(jié)構(gòu)如下圖:由上圖可知伶棒,左滑的操作按鈕是在UITableView的子view旺垒,所以我們可以在UITableView
的category
中hook掉layoutSubviews
方法,找到UISwipeActionPullView
的子view button肤无,設(shè)置字體顏色和大小先蒋。
代碼如下:
- (void)applyEditActionButtonStyle
{
if (self.editActionTitleColor) {//設(shè)置editActionTitleFont同理
NSArray *btns = [self __findSwipActionButtons];
for (UIButton *btn in btns) {
[btn setTitleColor:self.editActionTitleColor forState:UIControlStateNormal];
}
}
}
- (NSArray<UIButton *> *)__findSwipActionButtons{
if ([Common iOS11]) {
NSMutableArray *buttons = [NSMutableArray array];
for (UIView *extView in self.subviews) {
if ([NSStringFromClass(extView.class) isEqualToString:@"UISwipeActionPullView"]) {
for (UIButton *btn in extView.subviews) {
if ([btn isKindOfClass:[UIButton class]]) {
[buttons addObject:btn];//要返回所有的左滑出的button
}
}
}
}
return [buttons copy];
}
return nil;
}
3、遇到的問(wèn)題及原因分析
3.1 問(wèn)題是iOS 11上設(shè)置顏色有延遲宛渐,顏色有一個(gè)明顯的跳變竞漾,從系統(tǒng)默認(rèn)色跳轉(zhuǎn)到我設(shè)置的顏色
有問(wèn)題的代碼如下:
- (void)applyEditActionButtonStyle
{
if (self.editActionTitleColor) {
UIButton *btn = [self __findSwipActionButton];
[btn setTitleColor:self.editActionTitleColor forState:UIControlStateNormal];
}
}
- (UIButton *)__findSwipActionButton{
if ([Common iOS11]) {
for (UIView *extView in self.subviews) {
if ([NSStringFromClass(extView.class) isEqualToString:@"UISwipeActionPullView"]) {
for (UIButton *btn in extView.subviews) {
if ([btn isKindOfClass:[UIButton class]]) {
return btn;
}
}
}
}
}
return nil;
}
3.2 問(wèn)題原因分析
當(dāng)左滑一個(gè)cell后,直接操作左滑另一個(gè)cell窥翩,這個(gè)時(shí)候tableView上會(huì)有兩個(gè)UISwipeActionPullView
业岁,此時(shí)tableView的部分view層級(jí)如下圖所示:
而上面的代碼,在__findSwipActionButton
方法中寇蚊,找到其中一個(gè)UISwipeActionPullView
上面的button就直接返回了笔时,沒(méi)有設(shè)置第二個(gè)UISwipeActionPullView
的button的顏色,導(dǎo)致顯示了系統(tǒng)默認(rèn)色仗岸。
3.3 解決方法
將以上有問(wèn)題的代碼修改為以下代碼:找出所有的UISwipeActionPullView
允耿,返回UISwipeActionPullView
的button數(shù)組,對(duì)button數(shù)組進(jìn)行設(shè)置字體顏色和大小扒怖,這個(gè)數(shù)組最多有兩個(gè)元素较锡,因?yàn)樽蠡鱿乱粋€(gè)cell時(shí),上一個(gè)cell會(huì)逐漸消失盗痒,當(dāng)此cell左滑操作完成時(shí)蚂蕴,上一個(gè)左滑的cell也會(huì)完成消失。
解決后的代碼如2.2的示例代碼。