xib嵌套
封裝了一個view收捣,它自帶有xib届案。想讓它能在其他xib、SB中使用
1.綁定xib的File Owner
(此xib的所有者罢艾,管理這個xib的邏輯楣颠、交互等,類似于ViewController
對view
的管理)
(這里你可能會疑問為什么不直接綁定view為此類咐蚯,如下圖童漩。這種做法也可以,但只適用于用代碼創(chuàng)建的場景春锋,如自定義帶xib的UITableViewCell
矫膨,每個cell是由代碼創(chuàng)建的。不能內(nèi)嵌到其他xib期奔、SB中使用侧馅,后面有詳細解釋)
2.在view的.m文件中實現(xiàn)下面代碼就行了
- (instancetype)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self) {
[self loadViewFromXib];
}
return self;
}
- (void)loadViewFromXib
{
// 取xib中view的方法一:
UIView *contentView = [[NSBundle bundleForClass:[self class]] loadNibNamed:NSStringFromClass([self class]) owner:self options:nil].firstObject;
// 取xib中view的方法二:
// UINib *nib = [UINib nibWithNibName:NSStringFromClass([self class]) bundle:[NSBundle bundleForClass:[self class]]];
// UIView *contentView = [nib instantiateWithOwner:self options:nil].firstObject;
/*
這里取view有兩種方法,方法一一步完成,方法二拆成了兩步呐萌。
方法二的好處在于我們可以保留取出來的nib馁痴,以后直接用nib生成view,不會像方法一總是會重復去取nib肺孤。
方法二常見于帶xib的TableViewCell罗晕,因為cell會大量重用济欢,所以方法二取一次nib保存后,以后要用cell只用執(zhí)行它的第二句代碼來生成view小渊,更加高效
一般情況下法褥,兩個沒什么區(qū)別,用哪個看個人喜好
*/
contentView.frame = self.bounds;
contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth| UIViewAutoresizingFlexibleHeight;
[self addSubview:contentView];
}
xib可視化
可以讓封裝好的xib酬屉,在其他xib或者SB中實時預覽
只需在上面代碼基礎上加入以下三步:
- view的.h中聲明
IB_DESIGNABLE
半等。(聲明此視圖需要支持預覽)- 要寫
initWithFrame:
方法。(xcode預覽的工具梆惯,顯示view時會創(chuàng)建這個View酱鸭,此時走的view的這個初始化方法)- 用
[NSBundle bundleForClass:[self class]]]
取對對應的Bundle。(可能實時運行的預覽工具垛吗,取資源文件的位置和app實際運行時不一樣)
完整代碼如下:(以后可直接復制使用)
.h
IB_DESIGNABLE
@interface CustomView : UIView
@end
.m
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self loadViewFromXib];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self) {
[self loadViewFromXib];
}
return self;
}
- (void)loadViewFromXib
{
// 對于Bundle不太了解凹髓,但這里要用[NSBundle bundleForClass:[self class]]]取對對應的Bundle,而不是用mainBundle或者nil
UIView *contentView = [[NSBundle bundleForClass:[self class]] loadNibNamed:NSStringFromClass([self class]) owner:self options:nil].firstObject;
contentView.frame = self.bounds;
contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth| UIViewAutoresizingFlexibleHeight;
[self addSubview:contentView];
}
// 順便一提屬性使用
IBInspectable
可在xib的右側的屬性(Attributes inspector)標簽欄中看到
@property (nonatomic, assign) IBInspectable BOOL semicircle;///< 始終一般高度的圓角// 使用
IBOutlet
可在連接(Connections inspector)標簽欄中看到怯屉,一般用來連線到File Owner
@property (nonatomic, weak) IBOutlet id customDelegate;
如果一直沒顯示出來:
1.類名不能綁定在view上蔚舀,要綁在File Owner上,否則會死循環(huán)crash
2.使用下面的【view Debugging】方法
view Debugging
當為view增加 IB_DESIGNABLE
時锨络,可能經(jīng)常出現(xiàn) error: IB Designables: Failed to render and update auto layout status for UIView (i5M-Pr-FkT): The agent crashed
的情況
此時有兩種調(diào)試方法:
1.在xib或者sb中赌躺,選擇自定義視圖,然后選擇 Editor
- Debug Selected Views
羡儿。這會重新對這view運行 IBDesignableAgentCocoaTouch
礼患,可以進入視圖的斷點進行調(diào)試
2.在 ~/Library/Logs/DiagnosticReports
目錄中有命名為 IBDesignablesAgentCocoaTouch_*.crash
的崩潰日志,記錄了堆棧信息
預覽專用方法
預覽專用方法掠归,程序實際運行時不調(diào)用缅叠。
用于在其他xib、SB中預覽你customView時虏冻,配置一些參數(shù)的默認值肤粱,以便能完整的預覽到customView效果
/// 預覽時調(diào)用,程序實際運行時不調(diào)用
- (void)prepareForInterfaceBuilder
{
self.arrTitle = @[@"預覽", @"預覽文案", @"在程序運行時不會執(zhí)行厨相,預覽文案預覽文案", @"預覽文案领曼,在程", @"預覽文案,在程序運行時不會執(zhí)行預覽文案蛮穿,在程序運行時不會執(zhí)行"];
}
xib原理
為什么不先講原理呢庶骄?怕嚇跑你們??
xib本身是xml格式的資源文件,上面記錄了什么控件應該擺在哪里践磅,控件本身設置了哪些屬性等瓢姻,和你的圖片、音視頻差不多音诈,所以本身是無法"直接"繼承的幻碱。
是的,我們可以"間接"達到繼承的效果细溅,后面會說褥傍。
名詞釋義:
xib:xml格式的文件,記錄控件喇聊、屬性及其之間位置關系恍风。(我們在xcode中直接看到的)
nib:xib被加密、序列化后的二進制文件(data)誓篱。(app打包后朋贬,將包拆開后可以看到.nib后綴名的文件)
序列化:歸檔(將xib加密成nib的過程)
反序列化:解檔(將nib解密,提取到內(nèi)存中窜骄,成為我們能直接使用的類的過程)
頂級對象:xib面板左側對象邊欄中的最外層的對象锦募,如最外層的view。instantiateWithOwner:和loadNibNamed:owner:方法返回的數(shù)組中邻遏,保存的都是頂級對象(原諒我表述不清糠亩,自己的理解不深)
xib加載流程:
提取nib文件到內(nèi)存中
從Bundle
中取出nib
文件,為二進制文件
准验,加入到內(nèi)存中對原xib中所有view對象進行解檔
a) 從內(nèi)存中的二進制數(shù)據(jù)赎线,取出原xib
中的各view對應那部分data
b) 通過調(diào)用initWithCoder:
初始化方法,創(chuàng)建原xib
中的所有view糊饱,將上面的那部分data
作為入?yún)魅?br> c) 這里是每個view進行反序列化
垂寥,將二進制文件
轉為實際的類。實際上不需要我們親自來反序列化
另锋,在initWithCoder:
方法中調(diào)用[super initWithCoder:coder]
即可滞项,系統(tǒng)的根類中已經(jīng)默認做好了
d) 注意??:每個view(包括頂級對象view)在xib中綁定的什么類,就會創(chuàng)建這個類砰蠢。例如一個View沒有綁定類名蓖扑,默認系統(tǒng)的UIView類,那么實際就是調(diào)用的[UIView initWithCoder:aData]
台舱,這個view解檔完成后就是UIView的實例律杠;如果一個View綁定類名為CustomView,那么實際就是調(diào)用的[CustomView initWithCoder:aData]
竞惋,然后就進入到CustomView類中的initWithCoder:
方法了柜去,這個view解檔完成后就是CustomView的實例。
e) 注意??:在initWithCoder:
方法中拆宛,不能使用xib嗓奢、SB連線出來的屬性,此時連線的屬性都為nil浑厚,因為現(xiàn)在還沒開始關聯(lián)屬性關聯(lián)屬性和方法
對連線到自己類
股耽、File Owner
根盒、Object
中的屬性進行弱引用關聯(lián),并關聯(lián)事件物蝙。然后這三個地方就可以使用連線過來的屬性和響應連線的過來方法了炎滞。(下面會講怎么連線到這三個地方)解檔完成
原xib
中各個view解檔完成后,調(diào)用各自的awakeFromNib
方法诬乞,告訴你xib已經(jīng)完全ok册赛,可以直接使用了。現(xiàn)在你可以在awakeFromNib
方法中震嫉,使用xib森瘪、SB連線出來的屬性了。
拓展點:xib票堵、SB可以連線到哪些地方
1)連線到自己類
自己的東西(子視圖扼睬、手勢、Object類等)换衬,能通過連線痰驱,被自己使用,這沒毛病瞳浦。
2)連線到File Owner
自己的所有者使用自己東西担映,也挺合理。
File Owner
一般作為管理xib的地方叫潦,像ViewController
蝇完、包含此xib的視圖
3)連線到Object
Object
是任意類,一般是繼承于NSObject的邏輯類矗蕊,用于處理視圖中的邏輯部分短蜕,這就很厲害了。
Object
其實分為Object
和External Object
兩種傻咖,前者xib朋魔、SB會直接在解檔的時候創(chuàng)建一個,后者則是需要在xib初始化時卿操,傳入的已存在的實例警检,不由xib創(chuàng)建。
使用Object
很簡單害淤,直接拖入一個Object
扇雕,然后綁定類名,就可以關聯(lián)屬性及事件了
這里的CustonViewManager類窥摄,可以當做專門處理CustonView中邏輯的類
使用External Object
稍微復雜點镶奉,拖入一個External Object
后,需要先綁定類名(class)及標識符(Identifier)
這里的TestViewController是CustonView的File Owner,TestViewControllerManager類可以當做是處理TestViewController中邏輯的類
然后在xib初始化時哨苛,傳入
External Object
的實例鸽凶。最后就可以在TestViewControllerManager中也使用CustonView中的東西啦
所以,例如xib移国、SB中有一個button時吱瘩,我們?nèi)绻麑⑦@個button連線到這三個地方,那么在xib解檔后迹缀,這三個地方都能修改這個button的屬性。
同理蜜徽,如果將這個button的點擊事件連線到到這三個地方祝懂,那么這三個地方都能響應button的點擊事件(三個地方點擊事件的執(zhí)行順序暫時還沒測試過,不過我覺得這里的作用是分開執(zhí)行不相關聯(lián)的邏輯拘鞋,不能太依靠事件的執(zhí)行順序)砚蓬。
這樣就能給代碼瘦身,封裝出更優(yōu)雅的View盆色。不過也因為太靈活灰蛙,所以使用時需要謹防矯枉過正
拓展點:將類名綁File Owner和綁頂級對象view的區(qū)別
這點文章開頭
及xib加載流程
中都有提到過。
以CustonView.xib
為例:
你如果將頂級對象view的類名綁定為CustonView隔躲,那么在xib解檔過程中摩梧,對頂級對象view解檔后,返回的就是CustonView這個實例宣旱。也就是loadNibNamed: owner:self options:
這個方法返回的數(shù)組中仅父,你拿到的就是custonView的實例
你如果將File Owner的類名綁定為CustonView,那么CustonView類
是CustonView.xib
的管理者浑吟,CustonView.xib
只負責給CustonView類
提供打包好的view笙纤。也就是loadNibNamed: owner:self options:
這個方法返回的數(shù)組中,你拿到的就是UIView的實例
多數(shù)情況下组力,我們都是綁定File Owner的類名省容,為什么呢?舉個栗子??
我封裝了一個
RedButton
的控件燎字,它自帶有RedButton.xib
腥椒,里面是一些圖片、文案等轩触,且在RedButton.xib
中的綁定頂級對象view為RedButton寞酿。這時我在mainViewController.xib
中需要用到封裝好的RedButton
,我就拖一個button到xib脱柱,然后將類名改為RedButton伐弹。接下來我們在腦海中模擬一下
mainViewController.xib
解檔的整個過程:
mainViewController.xib
開始解檔,它要通過二進制數(shù)據(jù)(nib)
創(chuàng)建原xib
中所有的view,所以調(diào)用每個view的initWithCoder:
方法- 接著RedButton被調(diào)用
initWithCoder:
方法惨好,此時initWithCoder:
時沒有寫任何代碼的煌茴,程序繼續(xù)走,RedButton實例生成成功日川。但是最后我們發(fā)現(xiàn)蔓腐,
mainViewController.xib
中RedButton這部分是一片空白。這時我們回想一下就會發(fā)現(xiàn)龄句,mainViewController.xib
只是會通過initWithCoder:
方法創(chuàng)建了RedButton這個類回论,單純的創(chuàng)建這個類,并不會加載RedButton.xib
這個文件分歇,所以RedButton缺失了視圖元素傀蓉。那么我們將代碼改下,在
initWithCoder:
中加載RedButton.xib
职抡,將其頂級對象view作為自己子視圖:
- (instancetype)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self) {
[self loadViewFromXib];
}
return self;
}
- (void)loadViewFromXib
{
UINib *nib = [UINib nibWithNibName:NSStringFromClass([self class]) bundle:[NSBundle bundleForClass:[self class]]];
UIView *contentView = [nib instantiateWithOwner:self options:nil].firstObject;
contentView.frame = self.bounds;
[self addSubview:contentView];
}
重新運行程序后葬燎,會發(fā)現(xiàn)程序crash了,堆棧信息中顯示陷入了死循環(huán)缚甩。我們重新理一下現(xiàn)在的調(diào)用順序:
mainViewController.xib
開始解檔谱净,它要通過二進制數(shù)據(jù)(nib)
創(chuàng)建原xib
中所有的view,所以調(diào)用每個view的initWithCoder:
方法- 接著RedButton要開始解檔擅威,通過調(diào)用
[RedButton initWithCoder:aData]
壕探,此時initWithCoder:
中要加載RedButton.xib
RedButton.xib
開始解檔,調(diào)用每個view的initWithCoder:
方法裕寨,包括頂級對象view浩蓉。- 因為頂級對象view的類名綁定的是RedButton,頂級對象view開始解檔宾袜,調(diào)用
[RedButton initWithCoder:aData]
捻艳,果然進入了死循環(huán)這要怎么解決呢?將xib中
綁頂級對象view的類名
改為綁File Owner的類名
就行了庆猫。
這說明封裝的帶xib的view认轨,如果要支持嵌套在其他xib中,則不能綁定頂級對象view的類名月培,只能通過綁定File Owner的類名嘁字,將RedButton.xib
作為單純的視圖元素加到自己的view上。
這也就是為什么綁File Owner的類名的做法更常見杉畜。那不能將封裝的帶xib的view纪蜒,綁頂級對象view的類名么?可以的此叠,上面代碼不變纯续,xib綁頂級對象view的類名不變。不過只能用于代碼創(chuàng)建xib的場景,如VC中猬错,用代碼創(chuàng)建自定義view(
RedButon *btn = [self loadNibNamed:@"RedButton" owner:self options:].firstObject
),又例如在UITableView的代理中窗看,創(chuàng)建帶xib的Cell。
結論:在xib中
綁頂級對象view的類名:只能用于代碼創(chuàng)建此類
綁File Owner的類名:代碼創(chuàng)建此類倦炒、嵌套到其他xib中都可以(常用)
xib繼承
以聊天頁面為例(如QQ)显沈,里面的每條消息都是一行cell,大致有這幾種cell:文字消息行逢唤、圖片消息行拉讯、視頻消息行、紅包消息行鳖藕。這些cell都有共同的部分遂唧,就是左右的人物頭像,以及氣泡背景吊奢。
一般第一反應就是做成繼承的類型,父類cell中有共同部分纹烹,子類cell中只有各自差異化的東西页滚,如父類cell有頭像、氣泡铺呵,文字消息子cell中只有文字裹驰,圖片消息子cell中只有圖片。
具體怎么做呢片挂?別急幻林,還需要了解兩個東西:
1.子類xib中的元素,可以連線到父類中音念。不管是綁頂級對象view
還是綁File Owner
沪饺。
這里舉例不當,沒必要同時連線到父類和子類中闷愤,因為子類會繼承父類中的屬性整葡,希望別被我誤導了。
2.我一般使用UITableView時會開始就注冊cell讥脐,這樣就不用在- tableView: cellForRowAtIndexPath:
中判斷cell是不是存在遭居,因為注冊了cell后,然后從重用隊列中取cell時旬渠,如果取不到系統(tǒng)會自動創(chuàng)建一個新的cell返回給你俱萍。
下面是重點:
注冊cell有兩種方式:
1.使用[_tableView registerNib: forCellReuseIdentifier:]
方法: 通過nib創(chuàng)建cell
用于創(chuàng)建自帶xib的cell,也就是cell.xib中告丢,必須綁定頂級對象的類名為當前cell枪蘑。
創(chuàng)建時,會走cell的initWithCoder:
方法,不會走別的初始化方法2.使用
[_tableView registerClass: forCellReuseIdentifier:]
方法: 通過類名來創(chuàng)建cell
一般用于創(chuàng)建沒有xib的cell腥寇。如果cell有xib成翩,也要使用這種注冊方法怎么辦,在cell.xib中赦役,綁定File Owner為當前cell麻敌。
創(chuàng)建時,會走cell的initWithStyle: reuseIdentifier:
方法掂摔,不會走別的初始化方法
現(xiàn)在我們就可以試著想怎么實現(xiàn)上面說的聊天信息cell的繼承:
前提:代碼上术羔,子類cell都繼承父類cell,如文字消息cell
乙漓、圖片消息cell
级历、視頻消息cll
等,都繼承自父類消息cell
那么叭披,父類cell是否擁有xib寥殖、父類或子類cell的xib中的內(nèi)容是完整的還是一部分、這些xib是通過registerNib的方式注冊
還是通過registerClass的方式注冊
涩蜘,這些組合起來就有很多可能嚼贡。
方案一:
Demo: 方案一Demo
父類和子類都有各自的xib,父類的xib是公共部分同诫,子類的xib是差異部分粤策。(xib全部綁定的是File Owner)
子類通過registerClass注冊, 在初始化時误窖,先加載父類xib中內(nèi)容叮盘,addSubView到cell上。然后加載自己xib霹俺,addSubView到指定區(qū)域(氣泡)中柔吼。
先注冊cell (一定要使用registerClass
的方式注冊,不能是registerNib
)
// 首先使用registerClass的方式注冊子類cell
[_tableView registerClass:[TextChatCell class] forCellReuseIdentifier:NSStringFromClass([TextChatCell class])];
[_tableView registerClass:[ImageChatCell class] forCellReuseIdentifier:NSStringFromClass([ImageChatCell class])];
// 然后就可以用重用獲取cell了
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary *dict = _arrData[indexPath.row];
NSString *type = dict[@"type"];
if ([type isEqualToString:@"text"]) {
// text
TextChatCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([TextChatCell class]) forIndexPath:indexPath];
return cell;
} else {
// image
ImageChatCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([ImageChatCell class]) forIndexPath:indexPath];
return cell;
}
}
父類cell實現(xiàn)
@implementation BaseChatCell
#pragma mark - Life Circle
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
[self loadViewFromXib];
}
return self;
}
/// 加載父類xib
- (void)loadViewFromXib
{
UINib *nib = [UINib nibWithNibName:NSStringFromClass([BaseChatCell class]) bundle:[NSBundle mainBundle]];
UIView *contentView = [nib instantiateWithOwner:self options:nil].firstObject;
[self.contentView addSubview:contentView];
// 添加約束吭服,讓內(nèi)容充滿cell
contentView.translatesAutoresizingMaskIntoConstraints = NO;
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[contentView]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(contentView)]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[contentView]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(contentView)]];
}
@end
子類cell實現(xiàn)(這里以文字消息cell為例嚷堡,其他子類cell中代碼一模一樣)
@implementation TextChatCell
#pragma mark - Life Circle
- (void)loadViewFromXib
{
// 加載父類xib中內(nèi)容
[super loadViewFromXib];
// 加載當前類xib中內(nèi)容
[super loadChildViewFromXib];
}
/// 加載子類xib
- (void)loadChildViewFromXib
{
// 加載子類xib,將差異化的視圖元素艇棕,加載到父視圖指定區(qū)域內(nèi)
UINib *nib = [UINib nibWithNibName:NSStringFromClass([self class]) bundle:[NSBundle mainBundle]];
UIView *contentView = [nib instantiateWithOwner:self options:nil].firstObject;
[self.viewContent addSubview:contentView];
// 添加約束蝌戒,讓內(nèi)容充滿cell
contentView.translatesAutoresizingMaskIntoConstraints = NO;
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[contentView]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(contentView)]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[contentView]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(contentView)]];
// 做一些處理,其實這些也可以在xib直接設置好
contentView.backgroundColor = [UIColor clearColor];
self.viewContent.backgroundColor = [UIColor clearColor];
}
@end
因為每個子類中的loadChildViewFromXib
方法實現(xiàn)都是一樣的沼琉,所以我們可以把這個方法提取出來北苟,放到父類中,子類直接調(diào)用打瘪,免去了每次都在子類中實現(xiàn)一遍
@implementation BaseChatCell
#pragma mark - Life Circle
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
[self loadViewFromXib];
}
return self;
}
/// 加載父類xib
- (void)loadViewFromXib
{
UINib *nib = [UINib nibWithNibName:NSStringFromClass([BaseChatCell class]) bundle:[NSBundle mainBundle]];
UIView *contentView = [nib instantiateWithOwner:self options:nil].firstObject;
[self.contentView addSubview:contentView];
// 添加約束友鼻,讓內(nèi)容充滿cell
contentView.translatesAutoresizingMaskIntoConstraints = NO;
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[contentView]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(contentView)]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[contentView]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(contentView)]];
}
/// 加載子類xib
- (void)loadChildViewFromXib
{
// 加載子類xib傻昙,將差異化的視圖元素,加載到父視圖指定區(qū)域內(nèi)
UINib *nib = [UINib nibWithNibName:NSStringFromClass([self class]) bundle:[NSBundle mainBundle]];
UIView *contentView = [nib instantiateWithOwner:self options:nil].firstObject;
[self.viewContent addSubview:contentView];
// 添加約束彩扔,讓內(nèi)容充滿cell
contentView.translatesAutoresizingMaskIntoConstraints = NO;
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[contentView]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(contentView)]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[contentView]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(contentView)]];
// 做一些處理妆档,其實這些也可以在xib直接設置好
contentView.backgroundColor = [UIColor clearColor];
self.viewContent.backgroundColor = [UIColor clearColor];
}
@end
@implementation TextChatCell
#pragma mark - Life Circle
- (void)loadViewFromXib
{
// 加載父類xib中內(nèi)容
[super loadViewFromXib];
// 加載當前類xib中內(nèi)容
[super loadChildViewFromXib];
}
@end
方案二:
父類沒有xib,每個子類xib虫碉,都是完整的內(nèi)容贾惦。(xib全部綁定的是頂級對象view)
子類通過registerNib注冊cell。
先注冊cell(這里注冊方式與方案一相反敦捧,要用registerNib
的方式注冊须板,不能是registerClass
)
// 首先使用registerNib的方式注冊子類cell
[_tableView registerNib:[UINib nibWithNibName:NSStringFromClass([CustomerServiceTextCell class]) bundle:nil] forCellReuseIdentifier:NSStringFromClass([CustomerServiceTextCell class])];
[_tableView registerNib:[UINib nibWithNibName:NSStringFromClass([CustomerServiceImageCell class]) bundle:nil] forCellReuseIdentifier:NSStringFromClass([CustomerServiceImageCell class])];
// 然后就可以用重用獲取cell了
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomerServiceTextCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([CustomerServiceTextCell class]) forIndexPath:indexPath];
}
然后就沒了??,方案二的沒有代碼上需要處理的兢卵,唯一要注意的點就是子類xib中共同的視圖元素习瑰,都可以連線到父類中,然后就在父類的代碼中處理公共的邏輯秽荤。
結論:
方案一:方便以后的拓展甜奄、易維護。雖然理解上可能比方案二稍稍麻煩點窃款,但多用幾次就好了贺嫂,推薦。
方案二:很來很簡單雁乡,適合剛接觸xib的人,但強烈不推薦糜俗。你日后維護起來會很崩潰的踱稍,只要公共部分有改動,就需要去每個子類xib中修改悠抹,而且這里面一堆約束珠月,很容易出錯的。
當然還有其他組合出來的方案楔敌,但就我所知的情況中,和這兩種都是大同小異,有興趣的可以研究下其他的搭配脑又。