iOS之UITableView如何優(yōu)雅的插入數(shù)據(jù): 旋轉(zhuǎn)180°下拉加載cell頂置

姓名:唐來(lái)賓? 學(xué)號(hào):17101223417

轉(zhuǎn)載http://mp.weixin.qq.com/s/J0DKug2QSIaMguMTEkSrXQ

【嵌牛導(dǎo)讀】一般項(xiàng)目里面用到UITableView的概率還是灰常大的, 我的項(xiàng)目從一開(kāi)始也用了. 大概的來(lái)說(shuō)就是類似一個(gè)收件箱的功能, 推送來(lái)一條消息就加一個(gè)cell, 這是很簡(jiǎn)單的.

【嵌牛鼻子】數(shù)據(jù)插入,旋轉(zhuǎn)

【嵌牛提問(wèn)】如何簡(jiǎn)化數(shù)據(jù)插入過(guò)程?

【嵌牛正文】一. 概述

一般項(xiàng)目里面用到UITableView的概率還是灰常大的, 我的項(xiàng)目從一開(kāi)始也用了. 大概的來(lái)說(shuō)就是類似一個(gè)收件箱的功能, 推送來(lái)一條消息就加一個(gè)cell, 這是很簡(jiǎn)單的. 藍(lán)鵝, 接下來(lái)經(jīng)歷了兩次需求更改:

1. 增加'數(shù)據(jù)本地化'的功能;

2. 增加查看歷史消息功能, 也就是下拉加載更多的消息.

第一個(gè)還好說(shuō), 就是用FMDB弄了個(gè)簡(jiǎn)單的數(shù)據(jù)庫(kù), 差不多就是獲取數(shù)據(jù)的途徑變成從數(shù)據(jù)庫(kù)獲取而已;

在增加了第一個(gè)需求之后, 疊加提出第二個(gè)需求, 看起來(lái)也很簡(jiǎn)單哦, 不就是加數(shù)據(jù)嘛. 但是, 當(dāng)我開(kāi)始做起來(lái)的時(shí)候才發(fā)現(xiàn), 坑蠻多的.

這篇文章是基于我自己項(xiàng)目所寫(xiě)的, 可能在一些地方處理比較特殊并不具備"普世價(jià)值"; 但從開(kāi)發(fā)者學(xué)習(xí)的角度來(lái)說(shuō), 我始終認(rèn)為思路比代碼重要. 所以這里我可能在思路方面比較啰嗦點(diǎn), 直接要代碼的慎重選擇啊.

先說(shuō)一下, 需求二里面主要遇到的坑有兩個(gè):

坑一 : 下拉加載的10條消息, 顯示直接在第0-4條, 要看第5-9條的話又得反方向上滑

為了解決坑一, 將tableview和cell都旋轉(zhuǎn)了180°, 這時(shí)候, 坑二來(lái)了

坑二 : 在初始cell數(shù)量較少的時(shí)候, 推送新消息過(guò)來(lái)增加cell的時(shí)候?qū)е陆缑嫣鴦?dòng)

二. 項(xiàng)目過(guò)程

2.1需求分析

由于第一個(gè)需求太過(guò)簡(jiǎn)單, 所以就忽略啦. 這里直接講第二個(gè)需求的.

剛剛上面講的不是很清楚, 這里補(bǔ)充一下第二個(gè)需求的具體:

1.進(jìn)入到界面的時(shí)候, 里面要先顯示最多10條消息;

2.下拉可以加載歷史數(shù)據(jù)(每次10條);

3.當(dāng)有新消息推送過(guò)來(lái)的時(shí)候, 要添加在最底部, 并滾動(dòng)到最底部;

4.三日內(nèi)做完.

剛看到這個(gè)需求的時(shí)候, 我的第一個(gè)反應(yīng)是這太TM簡(jiǎn)單了, too simple! 看老夫如何在三天時(shí)間以內(nèi)用半天做完再用兩天半假裝沒(méi)做(tou)完(lan).

2.2 坑一

藍(lán)鵝, 忙活半天過(guò)后, 我發(fā)現(xiàn)自己too young too naive????. 這就是上面說(shuō)的坑一, 圖是這樣的, 可以看到點(diǎn)擊"消息+1"的時(shí)候還算正常, 但是下拉加載更多消息(10條)的時(shí)候, 都是停留在最頂部, 也就是上面坑一說(shuō)的, 要看第5-9條的時(shí)候, 得反方向上滑

正常的.gif

為了解決坑一, 我嘗試過(guò)調(diào)試NSIndexPath并且使用scrollToRowAtIndexPath:<#(nonnull nsindexpath=""> atScrollPosition:<#(uitableviewscrollposition)#> animated:<#(bool)#>]方法來(lái)各種折騰....再過(guò)了半天之后????放棄了, 下班, 對(duì), 下班!!!誰(shuí)說(shuō)程序猿都得加班的.

2.3 坑二

昨晚想了一(yi)下(晚)和簡(jiǎn)單的實(shí)踐(說(shuō)好的不加班呢, 變相加班????!), 發(fā)現(xiàn)在uitableview的底部使用inset...和scroll...方法拼接數(shù)據(jù)很完美, 腦洞大開(kāi)," 獨(dú)創(chuàng)"(后來(lái)發(fā)現(xiàn)網(wǎng)上也有)ios大法之乾坤大挪移----將整個(gè)tableview旋轉(zhuǎn)180°!!!!! 當(dāng)然cell也要旋轉(zhuǎn)180°.

旋轉(zhuǎn)的代碼分別是:

CGAffineTransform transform =CGAffineTransformMakeRotation(M_PI);

[tbV setTransform:transform];

cell的旋轉(zhuǎn):

CGAffineTransform transform =CGAffineTransformMakeRotation(M_PI);

[self.contentView setTransform:transform];

當(dāng)然, 使用mjrefresh的話, 就得用原來(lái)使用的mj_header換成mj_footer了(關(guān)于mjrefresh的使用).

弄好之后是這樣的, cell直接在最底部:

倒過(guò)來(lái)一.gif

這明顯是不行的, 為了使得cell數(shù)量比較少的時(shí)候可以頂置(實(shí)際是底置, 因?yàn)閠ableview旋轉(zhuǎn)了180°了), 于是想到了根據(jù)tableView.contentSize.height(關(guān)于 tableView.contentSize你想了解的)來(lái)設(shè)置tableView.contentInset, 代碼是這樣的

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{

if (tableView.contentSize.height < tableView.frame.size.height)

{

tableView.contentInset = UIEdgeInsetsMake(tableView.frame.size.height - tableView.contentSize.height - RSRealValue(120), 0, 0, 0);

}

}

運(yùn)行出來(lái)一看, 哇, 完美解決!!!! 藍(lán)鵝, 高興地太早了. 這時(shí)候下拉加載時(shí)沒(méi)問(wèn)題的, 但新加一條消息的時(shí)候, 新的cell會(huì)把原來(lái)的cell頂上去, 而不是拼接在最下面, 如圖:

倒過(guò)來(lái)contentInset.gif

經(jīng)過(guò)一番思考, 本人大致的認(rèn)為, 在新加入cell的時(shí)候, 原來(lái)的tableView.contentSize還是沒(méi)變, 也就是說(shuō)tableView.contentSize的布局其實(shí)還是只到了上一個(gè)cell的底部, 并以此往復(fù), 所以出現(xiàn)了上圖里面加了3條新消息再下滑的時(shí)候才出現(xiàn).

這時(shí)候, 又想到了一個(gè)方法, 可以嘗試監(jiān)聽(tīng)tableView.contentSize還動(dòng)態(tài)修改tableView.contentSize.....&%$#@!@#$%&%$過(guò)程省略幾百字, 直接說(shuō)結(jié)果吧, 然并卵. 而且, 在ios的UITableView里面, 并不是很推薦修改tableView.contentSize, 因?yàn)檫@個(gè)是蘋(píng)果自身維持動(dòng)態(tài)平衡的, 我們強(qiáng)心修改的話會(huì)影響其平衡, 而且在控制臺(tái)會(huì)出現(xiàn)警報(bào). 所以很不推薦.

就這樣又折騰了半天.....下午整個(gè)人都在想這個(gè)問(wèn)題. 終于在吃了一顆糖果之后, 想到一個(gè)方法:

為啥不通過(guò)記錄cell的總高度來(lái)代替tableView.contentSize, 然后設(shè)置一個(gè)透明的tableheaderview來(lái)代替設(shè)置tableView.contentInset快被自己的機(jī)智感動(dòng)了.

這樣既可以繞過(guò)上面說(shuō)的問(wèn)題了. 說(shuō)干就干.

需要在cell的model文件里面增加一個(gè)記錄本cell高度的屬性:

// 計(jì)算出來(lái)的cell的高度

@property (nonatomic, assign) CGFloat cellHeight;

同時(shí), 也得在控制器文件里面增加一個(gè)記錄所有cell總高度的屬性:

// cell的疊加高度

@property (nonatomic, assign) CGFloat cellsTotalHeight;

并且寫(xiě)了它的懶加載方法, 這樣每次在獲取總高度的時(shí)候都能保證是最新的

- (CGFloat)cellsTotalHeight{

CGFloat heightAll = 0;

for (int i = 0; i < self.dataMulArr.count; i ++) {

OneModel *model = self.dataMulArr[i];

heightAll = heightAll + model.cellHeight;

}

_cellsTotalHeight = heightAll;

NSLog(@"cell總高度: %f",heightAll);

return heightAll;

}

同時(shí), 返回頭部視圖和高度是這樣de(為了方便調(diào)試, 先把頭部視圖設(shè)置成有個(gè)半透明色)

#pragma mark- 返回頭部視圖

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{

UIView *headV = [[UIView alloc] init];

// ? ?headV.backgroundColor = [UIColor clearColor];

headV.backgroundColor = RSColorFromRGBA(0x00FF00, 0.5);

return headV;

}

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{

NSLog(@"頭部視圖高度中cell: %f", self.cellsTotalHeight);

CGFloat headHeight = 0;

if (self.cellsTotalHeight < self.tbV.frame.size.height)

{

headHeight = self.tbV.frame.size.height - self.cellsTotalHeight - RSRealValue(240);

}

return headHeight;

}

跑出來(lái)是這樣的:

倒過(guò)來(lái)加header.gif

這時(shí)候再把tableheaderview的背景色改成透明的, 就成了這樣了:

倒過(guò)來(lái)加header透明.gif

果然完美解決了, 這時(shí)候其實(shí)只剩一天時(shí)間假裝沒(méi)完(偷)成(lan)了.

不過(guò)還是要注意一下, 看圖倒過(guò)來(lái)加header.gif將tableheaderview改成透明之后, 新增cell還是會(huì)被tableheaderview擋住, 所以最后一個(gè)cell是點(diǎn)擊不到的. 因?yàn)槲翼?xiàng)目里面的cell不需要點(diǎn)擊, 所以這個(gè)問(wèn)題我可以忽略; 如果小伙伴項(xiàng)目里面的cell需要點(diǎn)擊的話, 就要將tableheaderview高度進(jìn)一步減去新增cell的高度哦. 這里我就不做具體代碼了, 小伙伴們自己探索一下把.

三. 小總結(jié)

總結(jié)起來(lái), 這里面幾個(gè)關(guān)鍵點(diǎn)是:

1.旋轉(zhuǎn)180°

2.不使用reloaddata方法, 而是使用inser....和scroll...兩個(gè)方法

3.通過(guò)增加tableheaderview來(lái)實(shí)現(xiàn)倒轉(zhuǎn)tableview之后cell的頂置, 并且動(dòng)態(tài)的改變tableheaderview的高度.

這個(gè)雖然只是項(xiàng)目的一小部分, 但每次解決問(wèn)題之后都能獲得成就感, 這就是碼農(nóng)單純的快樂(lè)吧.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,401評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,011評(píng)論 3 413
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 175,263評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,543評(píng)論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,323評(píng)論 6 404
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 54,874評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,968評(píng)論 3 439
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,095評(píng)論 0 286
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,605評(píng)論 1 331
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,551評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,720評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,242評(píng)論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 43,961評(píng)論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,358評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,612評(píng)論 1 280
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,330評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,690評(píng)論 2 370

推薦閱讀更多精彩內(nèi)容