目錄
2014年過的那么快,過年又那么塊,2015年又是飛快地節(jié)奏,真尼瑪感覺上帝是不是無聊使用了變速外掛開啟了加速模式~到現(xiàn)在博主都無法接受已經(jīng)上班的事實(shí)……在地鐵臉被擠在玻璃上的時(shí)候只能用眼神寫滿傻X射這個(gè)世界一臉??!原諒博主那么雞糞~因?yàn)楦缱罱×?,不嗨心~~,我想來去想不明白,博主每周健身4天,胸肌壓女友、拳頭比沙煲、吃喝健又康、體硬似野馬,怎么會(huì)生病呢?我苦思多日,終于有一天早上起床看了鏡子半個(gè)小時(shí)后我才頓悟,我靠~原來長(zhǎng)得帥真的是錯(cuò)!上帝在嫉妒我才讓我生病的~哈哈哈 咳咳~這是一個(gè)嚴(yán)肅的技術(shù)博客~是絕對(duì)拒絕惡俗低下的內(nèi)容的,大丈夫應(yīng)該心系天下才對(duì),最近柴靜和霧霾真的觸動(dòng)了我們每個(gè)人的心;某極端組織像嗨大了一樣,真的是屠龍寶刀在手,裝備任爆的節(jié)奏;近下的港島撐完雨傘又要趕人了……我真的是非常痛心疾首,維護(hù)世界和平一直是鄙人的愿望,現(xiàn)在的世界這么混亂,本人真的很慚愧,都怪我咯~~沒有因?yàn)槭裁?,所以今天博主要教大家怎么寫一個(gè)自己用著安逸,修改巴適,他人用起來又無比舒服的iOS庫(kù)!!
本人不才,接觸代碼的世界時(shí)間真心不是很久,對(duì)于系統(tǒng)底層優(yōu)化、框架級(jí)別設(shè)計(jì)、設(shè)計(jì)模式的效率優(yōu)劣等方面的學(xué)習(xí)和研究比不深刻,所以如果你是大神,你狠溜的話,我還是建議您路過呵呵一下然后就關(guān)了這個(gè)網(wǎng)頁(yè)吧,雕蟲小技無法入爾法眼啊~我不是怕被噴很菜(反正都被老師噴了二十年了……^_^)而是我對(duì)大神都是有敬畏之心的,不能說讓你看你就看,你可以試一下是吧,你也不喜歡看完后是Duang 那么多特效 特技……咳咳 反正這篇文章真的很菜~~~適合比我菜的菜鳥,慎讀。
不過嘛我們要寫一個(gè)庫(kù),能夠讓別人用,用起來要很舒服的,那肯定得要設(shè)計(jì)得當(dāng),肯定要熟悉平臺(tái),設(shè)計(jì)模式非常溜才行,這個(gè)沒錯(cuò)~但是平臺(tái)、架構(gòu)、設(shè)計(jì)這個(gè)東西這么復(fù)雜,我解釋大家也不懂,那我就不解釋了(你強(qiáng)迫癥發(fā)作死都要懂可自行找一個(gè)大學(xué),里面有老師~)
我發(fā)誓不扯BB了 我們一起來寫一個(gè)能被舒服舒服又舒服地調(diào)用的iOS庫(kù),最近衛(wèi)生紙漲價(jià)了,好煩,其實(shí)也是有原因的,因?yàn)楫吘股a(chǎn)費(fèi)用什么的也都…我頭上的磚頭誰(shuí)扔的?。???信不信我不打死你丫的……
假設(shè)我們要開發(fā)一個(gè)像微信朋友圈或者微博這玩意兒的東西,并且要有能隱藏和展開正文、正文中能夠識(shí)別富文本(網(wǎng)址、電話、@姓名……)、還要有圖片縮略圖而且點(diǎn)擊查看、能夠有回復(fù)、回復(fù)文中也要支持富文本……這些功能。像這樣
圖1
所謂君子生非異也 善假于物也。上面的功能這么多這么復(fù)雜自己寫,你確定你不是吃飽了撐著?經(jīng)理也說要敏捷開發(fā),所以二話不說閃現(xiàn)到code4app,code.cocoachina祭出最強(qiáng)殺器——搜索引擎,找到了這個(gè)庫(kù)WFCoretext https://github.com/TigerWf/WFCoretext 發(fā)現(xiàn)它完美符合我們的需求呀,棒棒噠
首先我們感謝WFCoretext 的作者的開源貢獻(xiàn),請(qǐng)收下我的膝蓋,我們馬上來用一用~
圖2
槽點(diǎn)不多
我們來分析分析它怎么搞得把
工程結(jié)構(gòu) 圖3
嗯額 還是比較簡(jiǎn)單的 View文件夾里面的是控件啦
圖4
具體實(shí)現(xiàn) 大家可以自己看啦,這位哥哥代碼風(fēng)格還是比較規(guī)范的,看起來不費(fèi)勁
Manager文件夾中是一些富文本匹配規(guī)則,其中YMTextData很重要 下面說
我們直接來看看怎么使用的把
點(diǎn)開WXViewController
導(dǎo)包并且聲明變量,變量在實(shí)現(xiàn)接下來的實(shí)現(xiàn)中會(huì)進(jìn)行初始化
#import "WXViewController.h"#import "YMTableViewCell.h"#import "ContantHead.h"#import "YMShowImageView.h"#import "YMTextData.h"#import "YMReplyInputView.h"#define dataCount 10#define kLocationToBottom 20#define kAdmin @"小虎-tiger"@interface WXViewController ()<UITableViewDataSource,UITableViewDelegate,cellDelegate,InputDelegate>{NSMutableArray *_imageDataSource;NSMutableArray *_contentDataSource;//模擬接口給的數(shù)據(jù)NSMutableArray *_tableDataSource;//tableview數(shù)據(jù)源NSMutableArray *_shuoshuoDatasSource;//說說數(shù)據(jù)源UITableView *mainTable;UIButton *replyBtn;YMReplyInputView *replyView ;}@end
這三個(gè)方法分別構(gòu)建初始化了一個(gè)tableview,初始化并賦值圖片數(shù)據(jù),初始化并賦值其他數(shù)據(jù)
- (void) initTableview;- (void)configImageData;- (void)loadTextData;
在loadTextData中會(huì)將數(shù)據(jù)包裝成YMTextData的數(shù)組,這樣一個(gè)tableCell里面的數(shù)據(jù)就使用一個(gè)YMTextData的數(shù)據(jù)
然后在
- (void)calculateHeight:(NSMutableArray *)dataArray
中會(huì)計(jì)算出數(shù)據(jù)所占用view的高度 這里面也就實(shí)現(xiàn)了 我們需求里面可以擴(kuò)展可以收縮的功能
計(jì)算完高度然后就重新加載tableview了 然后tableview的各種delegate方法 各種datasource方法就呼呼的運(yùn)行了
其中 以下方法中又再次使用了我們?cè)?
- (void)calculateHeight:(NSMutableArray *)dataArray
方法中計(jì)算出來的高度來設(shè)置tablecell的高度
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {YMTextData *ym = [_tableDataSource objectAtIndex:indexPath.row];BOOL unfold = ym.foldOrNot;return TableHeader + kLocationToBottom + ym.replyHeight + ym.showImageHeight + kDistance + (ym.islessLimit?0:30) + (unfold?ym.shuoshuoHeight:ym.unFoldShuoHeight) + kReplyBtnDistance;}
以下這個(gè)方法又把YMTextData 賦值給了YMTableViewCell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{static NSString *CellIdentifier = @"ILTableViewCell";YMTableViewCell *cell = (YMTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];if (cell == nil) {cell = [[YMTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];}cell.stamp = indexPath.row;cell.replyBtn.tag = indexPath.row;cell.replyBtn.appendIndexPath = indexPath;[cell.replyBtn addTarget:self action:@selector(replyAction:) forControlEvents:UIControlEventTouchUpInside];cell.delegate = self;[cell setYMViewWith:[_tableDataSource objectAtIndex:indexPath.row]];return cell;}
阿拉巴拉…… 呼呼
我就想問你一句 累不累?
現(xiàn)在我分析了一遍這個(gè)庫(kù),你知道該怎么用了么,不要懷疑自己的智商,我也要再看一遍才知道怎么用。
當(dāng)然我們不能懷疑作者對(duì)于開源技術(shù)做出的貢獻(xiàn)!我們也不能懷疑作者的開發(fā)技術(shù),畢竟這個(gè)庫(kù)的bug還是比較少的,作者是偉大崇高的!減少了世界的碳排量方便了你我他,為很多代碼工作者提供了方便,讓他們可以不加班,早早的回家陪老婆陪基友陪孩子陪寵物……所以我要再次感謝作者
但是作為一個(gè)有完美強(qiáng)迫癥的博主,問自己一句 為什么這個(gè)庫(kù)那么難用?因?yàn)樗y用
怎么才算是好用?系統(tǒng)自帶的組件,使用和學(xué)習(xí)起來那么容易?這應(yīng)該算是好用吧。
所以接下來,我們要開刀WXViewController 讓他DUANG的一下,變得使用起來 舒服舒服又舒服??!
我們不妨WXViewController的實(shí)現(xiàn)細(xì)節(jié)都封裝起來!它是一個(gè)tableview、它怎么計(jì)算高度,它的回復(fù)按鈕怎么生成……巴拉巴拉我都不想管?。∥业脑竿牵抑灰舆M(jìn)去數(shù)據(jù),就自動(dòng)生成一個(gè)朋友圈出來!!??!
有了愿望,急著召喚神龍也沒用!規(guī)則是要集齊龍珠呀?。?!好我們先干起來!整容WXViewController?。。?/span>
我們要開發(fā)一個(gè)東西就叫做 “朋友圈模板”吧 在“朋友圈模板.h”中要有一個(gè)“朋友圈模板Delegate” 然后里面要有一個(gè)方法
-(返回的數(shù)據(jù)*)每行朋友圈的數(shù)據(jù):index;
我們使用的時(shí)候就這樣:
真朋友圈.h
@interface 真朋友圈 : 朋友圈模板<朋友圈模板Delegate> @end
真朋友圈.m
@implementation 真朋友圈- (void)viewDidLoad {self.delegate = self;}-(返回的數(shù)據(jù)*)每行朋友圈的數(shù)據(jù):index{return [朋友圈數(shù)據(jù)數(shù)組 objectAtIndex:index];}@end
這樣就好了!你就再也不用關(guān)心朋友圈怎么實(shí)現(xiàn)了 你只要關(guān)系你的數(shù)據(jù)部分??!就問你Nice不Nice???
所以這里只要你開發(fā)好了“朋友圈模板.m”那么以后“朋友圈模板.h”和“朋友圈模板.m”就是你寫好的能被人舒服舒服又舒服調(diào)用的庫(kù)了!酷不酷??
博主就手把手教你怎么寫這個(gè)“朋友圈模板.m”吧 嘻嘻嘻 手把手哦 呵呵呵 手 把 手喲 博主是很有愛的哦~~~~
我們要開發(fā)一個(gè)DDRichTextViewController來代替WXViewController <——這個(gè)太難用了
我們先來寫寫DDRichTextViewController.h嘛
//學(xué)學(xué)系統(tǒng)組件 我們也來弄一個(gè)delegate和datasource~ 其實(shí)都是delegate為了更好地區(qū)分功能,datasource主要用來設(shè)置數(shù)據(jù)有關(guān)@PRotocol DDRichTextViewDelegate @required-(NSString*)senderName;//必須要實(shí)現(xiàn)!不然評(píng)論別人的時(shí)候沒名字 最恨匿名渣渣,自己叫的名字都不敢直接說?。?ldquo;有誰(shuí)知道我買充氣娃娃都匿名呢 呵呵,啊?為什么我心里想的會(huì)變成文字顯示出來?。。〖{尼?。?rdquo;@optional-(BOOL)hideReplyButtonForIndex:(NSInteger)index;//是否隱藏回復(fù)按鈕,有時(shí)候我們不讓人回復(fù) 就把回復(fù)按鈕隱藏起來了-(void)didPromulgatorPressForIndex:(NSInteger)index name:(NSString*)name;//發(fā)布者的頭像或者名字被點(diǎn)擊-(void)didRichTextPressedFromText:(NSString*)text index:(NSInteger)index;//正文的富文本被點(diǎn)擊的回調(diào)-(void)didRichTextPressedFromText:(NSString*)text index:(NSInteger)index replyIndex:(NSInteger)replyIndex;//評(píng)論的富文本被點(diǎn)擊的回調(diào)-(void)replyForIndex:(NSInteger)index replyText:(NSString*)text;//回復(fù)文字的內(nèi)容的回調(diào)@end@protocol DDRichTextViewDataSource @required-(YMTextData*)dataForRowAtIndex:(NSInteger)index;//這個(gè)就是每行需要的數(shù)據(jù)了!-(NSInteger)numberOfRowsInDDRichText;//需要返回多少行@end@interface DDRichTextViewController : UIViewController<UITableViewDataSource,UITableViewDelegate,cellDelegate,InputDelegate>@property (weak, nonatomic) id delegate;@property (weak, nonatomic) id dataSource;@end
然后就是DDRichTextViewController.m了
基本上就是對(duì)WXViewController.m的封裝了! 讓其內(nèi)部實(shí)現(xiàn)的細(xì)節(jié)都對(duì)使用者透明化
比如在DDRichTextViewController中實(shí)現(xiàn)了uitableView的datasource和delegate
在這個(gè)方法中 tableview需要顯示的行數(shù)就由繼承DDRichTextViewController的子類的datasource中的
-(NSInteger)numberOfRowsInDDRichText;
這個(gè)方法返回的數(shù)據(jù)作為參數(shù)!
比如這樣:
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{return [[self dataSource] numberOfRowsInDDRichText];}
所以當(dāng)我們使用我們自己寫的庫(kù)的時(shí)候根本不在乎這個(gè)方法
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
因?yàn)槲覀兎庋b到了
-(NSInteger)numberOfRowsInDDRichText;
類似其他實(shí)現(xiàn)以及方法都進(jìn)行了封裝
這當(dāng)中處理@required很簡(jiǎn)單,用戶必須已經(jīng)實(shí)現(xiàn)了 所以直接調(diào)用就好 。 但是 @optional的方法用戶不一定會(huì)去實(shí)現(xiàn),所以當(dāng)中最重要的就是要去判斷這個(gè)方法存不存在:方法如下
respondsToSelector:NSSelectorFromString(@“方法名:”) //這個(gè)凡是繼承NSObject的類都擁有這個(gè)方法 這個(gè)是基礎(chǔ)了,是運(yùn)行時(shí)判斷方法存不存在的
詳細(xì)如下
if ([self.delegate respondsToSelector:NSSelectorFromString(@"hideReplyButtonForIndex:")]) { //判斷hideReplyButtonForIndex方法存不存在 存在才會(huì)執(zhí)行如下的代碼if ([[self delegate] hideReplyButtonForIndex:indexPath.section]) {cell.hideReply = YES;}}
下面是詳細(xì)的代碼
(本來想貼詳細(xì)代碼的,博主一思忖!最好下載我的Demo進(jìn)行研究 這樣可以在方法之間跳轉(zhuǎn) 更能看得懂??!地址在文后!而且你們?cè)诓┲鞯腄emo項(xiàng)目中star一下 我就愛死你Y的了)
最后我們來看看怎么使用寫好的DDRichTextViewController
我們新建一個(gè)TestViewController
TestViewController.h#import "DDRichTextViewController.h"@interface TestViewController : DDRichTextViewController<DDRichTextViewDataSource,DDRichTextViewDelegate>@end
TestViewController.m
//// TestViewController.m// WFCoretext//// Created by David on 15/2/7.// Copyright (c) 2015年 tigerwf. All rights reserved.//#import "TestViewController.h"@interface TestViewController ()@end@implementation TestViewControllerNSMutableArray * ymDataArray;- (void)viewDidLoad {[super viewDidLoad];NSMutableArray MyDataArr = [[NSMutableArray alloc]init];//!!!!這里應(yīng)該自己初始化數(shù)據(jù)self.delegate = self;self.dataSource = self;}//下面兩個(gè)是datasource方法-(NSInteger)numberOfRowsInDDRichText{return 5;}-(YMTextData *)dataForRowAtIndex:(NSInteger)index{return [MyDataArr objectAtIndex:0];//!!!!!!!! MyDataArr 是一個(gè)YMTextData的數(shù)組??!所以你的朋友圈數(shù)據(jù)的每一項(xiàng)都必須是YMTextData或者繼承YMTextData的子類!!}//下面所有都是delegate的方法 朋友圈所有的特性都使用以下的delegate方法進(jìn)行控制 方法有可選和必選的 可自行實(shí)現(xiàn) 接口調(diào)用簡(jiǎn)單-(NSString *)senderName{return @"David";}-(BOOL)hideReplyButtonForIndex:(NSInteger)index{return NO;}-(void)didPromulgatorNameOrHeadPicPressedForIndex:(NSInteger)index name:(NSString *)name{UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"發(fā)布者回調(diào)" message:[NSString stringWithFormat:@"姓名:%@/n index:%d",name,index] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];[alert show];}-(void)didRichTextPressedFromText:(NSString*)text index:(NSInteger)index{UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"正文富文本點(diǎn)擊回調(diào)" message:[NSString stringWithFormat:@"點(diǎn)擊的內(nèi)容:%@/n index:%d",text,index] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];[alert show];}-(void)didRichTextPressedFromText:(NSString *)text index:(NSInteger)index replyIndex:(NSInteger)replyIndex{UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"評(píng)論的富文本點(diǎn)擊回調(diào)" message:[NSString stringWithFormat:@"點(diǎn)擊的內(nèi)容:%@/n index:%d /n replyIndex:%d",text,index,replyIndex] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];[alert show];}-(void)replyForIndex:(NSInteger)index replyText:(NSString*)text{UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"回復(fù)的回調(diào)" message:[NSString stringWithFormat:@"回復(fù)的內(nèi)容:%@/n index:%d",text,index] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];[alert show];}@end
效果如下
圖5
項(xiàng)目及Demo地址:https://github.com/daiweilai/DDRichText
博主對(duì)WXViewController的改動(dòng)還是頗多的,不單單是簡(jiǎn)單地封裝,我還做了表情和姓名的正則判斷,還對(duì)YMTableViewCell做了大量的邏輯修改,回調(diào)的接口做更改和增添也甚多!需要你親自去發(fā)現(xiàn)博主隱藏的愛,但無論如何這都是潦草的項(xiàng)目,想要正式的使用在企業(yè)開發(fā)中這還遠(yuǎn)遠(yuǎn)不夠的!沒有進(jìn)行模塊和單元的測(cè)試,其中圖片的處理方式也不好,這里我是直接要求用戶添加Image文件的 這個(gè)應(yīng)該改成 添加圖片地址,然后讓這個(gè)庫(kù)異步去請(qǐng)求顯示的……所以還是需要大家的開源精神和力量去貢獻(xiàn)自己的,燃燒自己的,騷年文章結(jié)束了
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注