深挖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,打算重新開始一個文章論述,若是有問題的話,歡迎評論區留言,咱們一塊兒討論!

若是您喜歡個人這篇文章,歡迎您給我點個贊,謝謝!

相關文章
相關標籤/搜索