深挖UITableViewCell-编辑多选模式下,引起的深思

  • 前言

在移动端平常开发中,列表**UITableView**的使用频率很是高,而TableView里主要用的就是UITableViewCell,不论是自定义cell,仍是系统的cell,仍是后期为了优化列表,都离不开操做cell,那么UITableViewCell就有必要研究一下了;至于为何要整理一篇关于Cell的文章,由于,搜了一下关于cell的文章,基本都是把头文件里面的方法简单介绍一下,没有介绍编辑模式下,cell的一些问题;ios

[说明规定]: 一些简单语法,便于说明问题:
* A-->B 意思是: A继承B,B是A的父类;git

另外,不要以为本身平时经常使用,而后想固然觉得,本身对于这个"出镜率"极高的控件极为熟悉,曾经我也那么觉得,然而,毕竟咱们:github

太年轻

  • 问题引导

遇到以下问题:猜猜看,多是什么缘由形成的?我在平时比较活跃的QQ交流群问了一下,而后石沉大海了......xcode

bug

这只是其中在cell编辑多选中遇到一个问题;app

还有一个就是,当用xib布局cell的时候,tableView进入编辑模式,多选不能全选cell,都是一些奇葩的问题;框架

  • 这篇文章主要说明什么问题
  1. Cell内部结构;
  2. 回答文章一开始的问题;
  3. Cell的重用机制;
  4. 能不能本身仿照系统Cell,实现一个继承自UIView而且重用的cell;
  • 一.cell内部结构

咱们知道,cell能够根据不一样的style显示不一样的类型;
好比下面的几种:ide

  1. 右边显示感叹号或者对勾;
  2. 编辑模式,左边显示勾选框;
  • Cell内部有什么
  1.  cell的继承关系

首先,OC中,全部的类都是对象,都是继承自NSObject,这个元类;每一个对象都有一个__isa__指针指向它的父类,实例对象的isa指针指向建立他的本类,类对象isa指向它的父类,元类指向它自己;这一块不作讨论;工具

不知你是否好奇,为何对象都有一个isa指针?其实,OC对象中isa指针,并非OC独有的,在Python中,也有相似的,isa分开来就是:布局

is a ,后面是省略的 kind of ,合起来就是 is a kind of ...翻译过来就是:是....的一类或者跟...是同一类的;优化

好理解,子类继承父类,即是 Son -> Father,B is A,就是B继承A;

固然以UI开头的属于UIKIt框架范畴,可是,全部的对象都是继承自NSObject;

 UITableViewCell --> UIView --> UIResponder --> NSObject

  • 工具:Runtime动态获取cell内部控件;

经过获取cell内部私有的子类,咱们知道,除了TextLable,ContentView,ImageView等,还有重用标识符**reuseIdentifier**

cell内部的控件结构图以下:
cell内部结构

Runtime获取一个类的中全部的私有属性:
[备注]:须要导入Runtime相关的头文件
#import <objc/runtime.h> #import <objc/message.h>_

unsigned int count;
Ivar *ivarList = class_copyIvarList([cell class], &count);
for (int i = 0; i < count; i++) {
Ivar ivar = ivarList[i];
NSLog(@"%s", ivar_getName(ivar));
}
free(ivarList);

 

2017-11-30 22:10:42.095 UITtableViewCell[66184:9589083] _tableView
2017-11-30 22:10:44.336 UITtableViewCell[66184:9589083] _layoutManager
2017-11-30 22:10:46.753 UITtableViewCell[66184:9589083] _target
2017-11-30 22:10:48.696 UITtableViewCell[66184:9589083] _editAction
2017-11-30 22:10:50.070 UITtableViewCell[66184:9589083] _accessoryAction
2017-11-30 22:10:51.967 UITtableViewCell[66184:9589083] _oldEditingData
2017-11-30 22:10:51.967 UITtableViewCell[66184:9589083] _editingData
2017-11-30 22:10:51.967 UITtableViewCell[66184:9589083] _rightMargin
2017-11-30 22:10:51.967 UITtableViewCell[66184:9589083] _indentationLevel
2017-11-30 22:10:51.967 UITtableViewCell[66184:9589083] _indentationWidth
2017-11-30 22:10:51.968 UITtableViewCell[66184:9589083] _reuseIdentifier
2017-11-30 22:10:51.968 UITtableViewCell[66184:9589083] _floatingContentView
2017-11-30 22:10:51.968 UITtableViewCell[66184:9589083] _lineBreakModeBeforeFocus
2017-11-30 22:10:51.968 UITtableViewCell[66184:9589083] _contentView
2017-11-30 22:10:51.968 UITtableViewCell[66184:9589083] _imageView
2017-11-30 22:10:51.968 UITtableViewCell[66184:9589083] _textLabel
2017-11-30 22:10:51.968 UITtableViewCell[66184:9589083] _detailTextLabel
2017-11-30 22:10:51.969 UITtableViewCell[66184:9589083] _backgroundView
2017-11-30 22:10:51.969 UITtableViewCell[66184:9589083] _selectedBackgroundView
2017-11-30 22:10:51.969 UITtableViewCell[66184:9589083] _multipleSelectionBackgroundView
2017-11-30 22:10:51.974 UITtableViewCell[66184:9589083] _selectedOverlayView
2017-11-30 22:10:51.974 UITtableViewCell[66184:9589083] _selectionFadeDuration
2017-11-30 22:10:51.974 UITtableViewCell[66184:9589083] _backgroundColor
2017-11-30 22:10:51.974 UITtableViewCell[66184:9589083] _separatorColor
2017-11-30 22:10:51.975 UITtableViewCell[66184:9589083] _separatorEffect
2017-11-30 22:10:51.975 UITtableViewCell[66184:9589083] _topShadowColor
2017-11-30 22:10:51.975 UITtableViewCell[66184:9589083] _bottomShadowColor
2017-11-30 22:10:51.975 UITtableViewCell[66184:9589083] _sectionBorderColor
2017-11-30 22:10:51.975 UITtableViewCell[66184:9589083] _floatingSeparatorView
2017-11-30 22:10:51.975 UITtableViewCell[66184:9589083] _topShadowAnimationView
2017-11-30 22:10:51.976 UITtableViewCell[66184:9589083] _bottomShadowAnimationView
2017-11-30 22:10:51.976 UITtableViewCell[66184:9589083] _badge
2017-11-30 22:10:51.976 UITtableViewCell[66184:9589083] _unhighlightedStates
2017-11-30 22:10:51.976 UITtableViewCell[66184:9589083] _highlightingSupport
2017-11-30 22:10:51.976 UITtableViewCell[66184:9589083] _selectionSegueTemplate
2017-11-30 22:10:51.976 UITtableViewCell[66184:9589083] _accessoryActionSegueTemplate
2017-11-30 22:10:51.977 UITtableViewCell[66184:9589083] _accessoryActionPreviewingSegueTemplateStorage
2017-11-30 22:10:51.977 UITtableViewCell[66184:9589083] _accessoryView
2017-11-30 22:10:52.008 UITtableViewCell[66184:9589083] _editingAccessoryView
2017-11-30 22:10:52.008 UITtableViewCell[66184:9589083] _customAccessoryView
2017-11-30 22:10:52.009 UITtableViewCell[66184:9589083] _customEditingAccessoryView
2017-11-30 22:10:52.009 UITtableViewCell[66184:9589083] _separatorView
2017-11-30 22:10:52.009 UITtableViewCell[66184:9589083] _topSeparatorView
2017-11-30 22:10:52.009 UITtableViewCell[66184:9589083] _topShadowView
2017-11-30 22:10:52.010 UITtableViewCell[66184:9589083] _editableTextField
2017-11-30 22:10:52.010 UITtableViewCell[66184:9589083] _lastSelectionTime
2017-11-30 22:10:52.010 UITtableViewCell[66184:9589083] _deselectTimer
2017-11-30 22:10:52.010 UITtableViewCell[66184:9589083] _textFieldOffset
2017-11-30 22:10:52.010 UITtableViewCell[66184:9589083] _indexBarWidth
2017-11-30 22:10:52.010 UITtableViewCell[66184:9589083] _separatorInset
2017-11-30 22:10:52.011 UITtableViewCell[66184:9589083] _backgroundInset
2017-11-30 22:10:52.011 UITtableViewCell[66184:9589083] _returnAction
2017-11-30 22:10:52.011 UITtableViewCell[66184:9589083] _selectionTintColor
2017-11-30 22:10:52.011 UITtableViewCell[66184:9589083] _accessoryTintColor
2017-11-30 22:10:52.011 UITtableViewCell[66184:9589083] _reorderControlImage
2017-11-30 22:10:52.012 UITtableViewCell[66184:9589083] _menuGesture
2017-11-30 22:10:52.012 UITtableViewCell[66184:9589083] _representedIndexPath
2017-11-30 22:10:52.012 UITtableViewCell[66184:9589083] _focusable
2017-11-30 22:10:52.013 UITtableViewCell[66184:9589083] _swipeToDeleteConfirmationView
2017-11-30 22:10:52.013 UITtableViewCell[66184:9589083] _swipeToDeleteCancelationGesture
2017-11-30 22:10:52.013 UITtableViewCell[66184:9589083] _clearBlendingView
2017-11-30 22:10:52.013 UITtableViewCell[66184:9589083] _swipeToDeleteDistancePulled
2017-11-30 22:10:52.013 UITtableViewCell[66184:9589083] _sectionCornerRadius
2017-11-30 22:10:52.014 UITtableViewCell[66184:9589083] _sectionBorderWidth
2017-11-30 22:10:52.014 UITtableViewCell[66184:9589083] _defaultMarginWidth
2017-11-30 22:10:52.014 UITtableViewCell[66184:9589083] _editControlFocusGuide
2017-11-30 22:10:52.014 UITtableViewCell[66184:9589083] _reorderControlFocusGuide
2017-11-30 22:10:52.014 UITtableViewCell[66184:9589083] _constants
2017-11-30 22:10:52.014 UITtableViewCell[66184:9589083] _tableCellFlags
2017-11-30 22:10:52.015 UITtableViewCell[66184:9589083] _isLayoutEngineSuspended

 

  • 二 文章一开始的问题
  1. 2.1 为何会有这个问题?

项目中,基本上都是多人协做开发,有些UI是复用的,团队中,又没有__codeReview__,每一个人对本身要求又不同,在平常开发中,因为咱们偷懒,能少写一点就少写一点,而文章出现的自定义cell正好是copy过来的,也没检查,当在非编辑模式下,显示正常;当在编辑模式下,就出问题了?

  •  解决办法


首先,在编辑模式下,正常的话,cell总体发生位移了,那么,只要涉及到控件位移的,第一就是打印frame,咱们看下,编辑时和非编辑状况下,cell的frame变化状况:

  • tableView非编辑下,cell的frame:

 非编辑cell Frame:<UITableViewCell: 0x7f9bd2020600; frame = (0 0; 320 44)

  • tableView编辑下,cell的frame

编辑下cell Frame:<UITableViewCell: 0x7f9bd401ea00; frame = (0 0; 320 44);

咱们惊奇的发现,两种模式下,cell的frame竟然是一致的,那也就是说:
编辑状态下,cell的总体位移不是经过修改cell自己的frame实现的;

接下来,cell内部还有一个contentView,咱们打印它的frame:

  • tableView非编辑下,cell.contentView的frame:

 非编辑cell Frame:<UITableViewCellContentView: 0x7f9fc31374a0; frame = (0 0; 320 44);

  • tableView编辑下,cell.contentView的frame

 编辑下cell Frame:<UITableViewCellContentView: 0x7fb522c02070; frame = (0 0; 320 44);

我靠,contentView的frame也是一致的,奇怪,那tableView,编辑下,怎么实现cell的总体位移呢?

既然,cell的自己的frame和cell内部contentView的frame,在编辑和非编辑模式下,frame在打印出来,结果并无改变,而实际上,在编辑模式下,cell明显发生位移了,接下来,咱们看一下cell的的视图层级关系:

  •  cell 的视图层级关系

进入xcode,视图层级关系,以下:

层级关系

经过视图层级,咱们能够看出,在编辑模式下,每个cell都动态添加了
UITableViewCellEditControl的控件,而这个editControl的并无add到contentView中,而是add在cell自己中,所以,若是自定义cell,布局相对cell自己,编辑模式,cell内部子控件就不会总体移动,必须相对于contentView;

其实,cell自己就是一个View,其内部又内置了一个容器view---ContentView,而ContView的文档说明以下:

  If you want to customize cells by simply adding additional views, you should add them to the content view so they will be positioned appropriately as the cell transitions into and out of editing mode. 就是说,若是想自定义cell,建立的子控件,如lable,imgView等,建议最好把子控件添加到ContentView中,这时候,在cell动画的时候,子控件也会随着ContView一块动画;

  •  2.2 自定义cell中,子控件不放在cell.contentView中,行不行?

问号

行啊,UI显示是没问题,可是,若是cell涉及动画,或者编辑模式下,多选,总体cell往右移动,这时候,若是子控件没有添加到contentView中,就会出现文章一开始的问题

  • 三 建议及后续

这篇文章,原本想经过cell的frame来探究编辑模式下,系统如何实现cell的总体移动,可是,frame竟然是一致的,可是,经过层级关系,咱们也知道,contentView在编辑状态下,frame改变了;

  • 建议

所以,建议:咱们在平常开发中,尤为是团队开发中,在自定义tableVIewcell的时候,布局相对contentView布局,不要像以下这样布局:如下代码就是罪魁祸首!

[self.videoCoverImgView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(weakSelf).offset(15*X_WidthScale);
make.top.equalTo(weakSelf).offset(15*Y_HeightScale);
make.width.offset(130*X_WidthScale);
make.height.offset(74*Y_HeightScale);
}];

 

[点击获取文章涉及代码]:https://github.com/lucyios/UITableViewCell.git

  • 后续

cell的重用机理及尝试模仿写一个cell,打算重新开始一个文章论述,若是有问题的话,欢迎评论区留言,咱们一块儿讨论!

若是您喜欢个人这篇文章,欢迎您给我点个赞,谢谢!

相关文章
相关标签/搜索