前言
- 微信朋友圈一直以來(lái)都是iOS開發(fā)人員爭(zhēng)相模仿的界面,主要是其包含了豐富的iOS所需知識(shí)點(diǎn),以及常用的功能模塊。當(dāng)然各個(gè)功能模塊實(shí)現(xiàn)過(guò)程中的細(xì)節(jié)處理以及用戶體驗(yàn)的優(yōu)化往声,這才是我們開發(fā)者在日常開發(fā)中需要關(guān)注和加強(qiáng)的地方。
- 本文筆者將著重分析微信朋友圈實(shí)現(xiàn)的具體過(guò)程以及細(xì)節(jié)處理操刀,爭(zhēng)取把里面的所有知識(shí)點(diǎn)烁挟,模塊雖小,但五臟俱全骨坑,其中最主要分析的是朋友圈的界面布局的細(xì)節(jié)處理以及性能優(yōu)化撼嗓。希望為大家提供一點(diǎn)思路,少走一些彎路欢唾,填補(bǔ)一些細(xì)坑且警。文章僅供大家參考,若有不妥之處礁遣,還望不吝賜教斑芜,歡迎批評(píng)指正。
- 微信朋友圈的基本架構(gòu)是基于
MVVM + RAC + ViewModel-Based Navigation
來(lái)實(shí)現(xiàn)的祟霍,如若不懂杏头,還請(qǐng)點(diǎn)擊iOS 基于MVVM + RAC + ViewModel-Based Navigation的微信開發(fā)(一)。 - 微信朋友圈的界面控件布局和富文本顯示內(nèi)容沸呐,主要是使用YYKit來(lái)完成的醇王,若對(duì)其不熟練的,請(qǐng)事先做好準(zhǔn)備哦崭添。
分析
前期在敲代碼之前寓娩,需要著重分析一下整個(gè)微信朋友圈界面的實(shí)現(xiàn)方案,這可能是本篇文章的核心所在了(PS:這里特別提醒一下廣大開發(fā)者呼渣,在實(shí)現(xiàn)某一個(gè)功能前棘伴,請(qǐng)務(wù)必確定一個(gè)實(shí)現(xiàn)方案,可能實(shí)現(xiàn)的方案千千萬(wàn)屁置,這就需要開發(fā)者通過(guò)自身的理解來(lái)確定一個(gè)最優(yōu)的方案來(lái)實(shí)現(xiàn)焊夸,而不是一昧毫無(wú)頭緒的敲代碼,造成后期又得重新迭代的悲勭掷纭4镜亍2篮K荨)颇象。微信朋友圈的效果圖如下(PS:萬(wàn)惡的馬賽克...)。
當(dāng)然整體的界面的布局還是比較復(fù)雜的并徘,前期看了UI還是挺讓人望而卻步的遣钳。首先,我們可以確定的是整體是利用UITableView
來(lái)實(shí)現(xiàn)的麦乞,是不是大家已經(jīng)隱隱約約感受到還是原來(lái)的配方蕴茴,還是熟悉的味道
,相同的tableView
姐直,變得只是Cell
罷了倦淀。其次,筆者經(jīng)過(guò)多日在GitHub
上搜尋一些實(shí)現(xiàn)微信朋友圈的開發(fā)的Demo
声畏,以及做了大量的市場(chǎng)調(diào)研和內(nèi)容對(duì)比撞叽,發(fā)現(xiàn)最具代表性的兩個(gè)Demo
分別是:gsdios/GSD_WeiXin和zhengwenming/WeChat,其他Demo
大多數(shù)都是參考這兩個(gè)Demo
來(lái)做的插龄,當(dāng)然這兩個(gè)Demo
實(shí)現(xiàn)微信朋友圈的方法涉及到兩個(gè)不同的方案愿棋,筆者就帶大家簡(jiǎn)單分析一下各自的方案實(shí)現(xiàn)過(guò)程以及目前存在的弊端(PS:這里所謂的弊端,只是針對(duì)微信朋友圈而言的)均牢。兩者的界面模塊劃分如下(PS: ① 紅色框 糠雨, ②:綠色框
):
當(dāng)然這兩個(gè)
Demo
的實(shí)現(xiàn)朋友圈的 共同之處
就是:將圖上所示的紅框①
整體用一個(gè)UITableViewCell
來(lái)展示。不同之處
就是:圖上所示的綠框②
的控件選取不同罷了徘跪。UITableViewCell
上布局子控件相對(duì)于大家肯定是小菜一碟甘邀,這里筆者就針對(duì)兩個(gè)Demo
在綠框②
的控件的選取上做文章以及分析其目前存在的弊端。當(dāng)然這兩個(gè)方案目前都不是最最優(yōu)化的方案垮庐,通過(guò)分析其中存在弊端松邪,逐漸引申出比較令人合理的方案,當(dāng)然筆者最終會(huì)給出自己的方案突硝,但也許未必是最優(yōu)的方案测摔,更好的方案或許就存在大家的手中,筆者這里主要強(qiáng)調(diào)的是 知其然解恰,知其所以然
锋八。話不多說(shuō)篡撵,Let's Do It琳疏!
-
方案一 【gsdios/GSD_WeiXin】
該方案將綠框②
的控件選取的是一個(gè)普通的UIView
吮炕,當(dāng)然內(nèi)部顯示文本(評(píng)論羡宙、回復(fù)冀宴、點(diǎn)贊
)的子控件用的是UILabel
來(lái)展示政冻。雖然這種寫起來(lái)比較通俗易懂牢硅,就是根據(jù)評(píng)論列表
和點(diǎn)贊列表
的內(nèi)容蒙谓,不斷修改內(nèi)部UILabel
的frame
來(lái)達(dá)到要求,但是卻帶來(lái)了如下的弊端:-
布局復(fù)雜:考慮到
綠框②
內(nèi)部子控件的布局的復(fù)雜性欺嗤,其作者采用的是其自己寫的SDAutoLayout來(lái)實(shí)現(xiàn)参萄,筆者對(duì)SDAutoLayout用的也不是非常熟練,關(guān)于其布局代碼的實(shí)現(xiàn)請(qǐng)留意其Demo
的SDTimeLineCellCommentView.h/m
文件即可煎饼,盡管其內(nèi)部布局代碼看起來(lái)還算簡(jiǎn)單讹挎,但是如果我們不使用SDAutoLayout,那么采用傳統(tǒng)的frame
布局吆玖,想想還是比較復(fù)雜的筒溃,比如:我們要計(jì)算出紅框①(UITableViewCell)
的高度,首先需要計(jì)算出綠框②
內(nèi)部所有子控件(UILabel
)的尺寸沾乘,從而推算出綠框②
的整體高度怜奖,最終方能確定紅框①(UITableViewCell)
的高度。筆者猜想該作者這里可能主要是為了凸顯SDAutoLayout的自動(dòng)布局的強(qiáng)大和便捷翅阵,好一個(gè)項(xiàng)莊舞劍歪玲,意在沛公
呀。 -
動(dòng)態(tài)創(chuàng)建:我們知道
紅框①(UITableViewCell)
是支持復(fù)用的怎顾,這是毋庸置疑的读慎,但是我們知道每一條說(shuō)說(shuō)(紅框①
)中包含的評(píng)論列表的個(gè)數(shù)是不一樣且Cell
高度也會(huì)不一樣。這樣就會(huì)涉及到當(dāng)用戶滾動(dòng)朋友圈列表且cell
復(fù)用的時(shí)候槐雾,綠框②
內(nèi)部的子控件的個(gè)數(shù)也是動(dòng)態(tài)的夭委,可能增多,又可能減少募强,這樣就造成了動(dòng)態(tài)增加或刪除綠框②
內(nèi)部的子控件株灸,想必大家都知道盡量不要在UITableViewCell
中動(dòng)態(tài)創(chuàng)建子控件,這是比較耗性能的擎值,常規(guī)的做法都是事先在- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(nullable NSString *)reuseIdentifier
一口氣創(chuàng)建所有你要顯示的控件慌烧,這樣你只需要根據(jù)數(shù)據(jù)的屬性來(lái)顯示或隱藏某個(gè)子控件即可,這樣就避免了動(dòng)態(tài)創(chuàng)建子控件的場(chǎng)景鸠儿。但是由于朋友圈列表的每條說(shuō)說(shuō)的評(píng)論列表個(gè)數(shù)是不能事先確定的屹蚊,所以必然會(huì)存在綠框②
動(dòng)態(tài)創(chuàng)建子控件的悲劇。 -
不支持大數(shù)據(jù):對(duì)于上面動(dòng)態(tài)創(chuàng)建控件的問(wèn)題进每,其實(shí)該作者在內(nèi)部
SDTimeLineCellCommentView.h/m
也是做了優(yōu)化處理的汹粤,其做法主要是將動(dòng)態(tài)創(chuàng)建的子控件(UILabel
)裝進(jìn)一個(gè)數(shù)組(commentLabelsArray
)里面,這樣可以減少一部分的動(dòng)態(tài)創(chuàng)建子控件過(guò)程田晚,但是還是會(huì)存在動(dòng)態(tài)創(chuàng)建子控件嘱兼,其主要邏輯就是根據(jù)你傳進(jìn)來(lái)的說(shuō)說(shuō)的評(píng)論列表的個(gè)數(shù) (commentItemsArray.count
)與commentLabelsArray.count
比較罷了,如果前者小于等于后者贤徒,就不需要?jiǎng)討B(tài)創(chuàng)建芹壕,只是對(duì)commentLabelsArray
中的子控件做顯示和隱藏處理即可汇四;反之如果前者大于后者,這需要?jiǎng)討B(tài)創(chuàng)建(commentItemsArray.count - commentLabelsArray.count
)個(gè)子控件踢涌,然后又被加入到數(shù)組commentLabelsArray
里面的過(guò)程通孽。關(guān)鍵代碼如下所示:
首先微信朋友圈的評(píng)論列表的個(gè)數(shù)是支持大數(shù)據(jù)的(PS:筆者瞎猜的…),那就必須確保綠框②
能支持大數(shù)據(jù)的顯示斯嚎,顯然隨著評(píng)論列表的個(gè)數(shù)逐漸增多利虫,以及UITableViewCell
的不斷復(fù)用挨厚,則綠框②
的commentLabelsArray
里面裝的子控件也會(huì)越來(lái)越多且保持只增不減的趨勢(shì)堡僻,這樣該方案就顯得比較的無(wú)力了。
- (void)setCommentItemsArray:(NSArray *)commentItemsArray{ _commentItemsArray = commentItemsArray; long originalLabelsCount = self.commentLabelsArray.count; long needsToAddCount = commentItemsArray.count > originalLabelsCount ? (commentItemsArray.count - originalLabelsCount) : 0; for (int i = 0; i < needsToAddCount; i++) { MLLinkLabel *label = [MLLinkLabel new]; [self addSubview:label]; [self.commentLabelsArray addObject:label]; } }
以上就是【gsdios/GSD_WeiXin】目前筆者發(fā)現(xiàn)其存在的些許問(wèn)題以及談?wù)劰P者個(gè)人的一些理解疫剃。當(dāng)然這個(gè)方案在針對(duì)大量的評(píng)論數(shù)據(jù)的處理上或許稍有吃力钉疫,但是如果當(dāng)評(píng)論列表的個(gè)數(shù)是固定,例如:優(yōu)酷視頻的評(píng)論回復(fù)(如下圖)巢价。這個(gè)方案也不失為一個(gè)好的解決方案牲阁。所以說(shuō)業(yè)務(wù)場(chǎng)景不同,實(shí)現(xiàn)方案不同壤躲,可見(jiàn)在敲代碼之前城菊,先思考后確定實(shí)現(xiàn)方案是多么重要。
YouKu_UI.png -
布局復(fù)雜:考慮到
-
方案二 【zhengwenming/WeChat】
該方案將綠框②
的控件選取的是一個(gè)UITableView
碉克,也就是說(shuō)Cell(紅色框①)
里面嵌套了一個(gè)UITableView
凌唬,其內(nèi)部子控件就是UITableViewCell
來(lái)處理,后面的處理其實(shí)就跟我們平常處理UITableView
的方法一樣漏麦,創(chuàng)建TableView
客税,遵守協(xié)議,實(shí)現(xiàn)協(xié)議方法… 撕贞,可能會(huì)不習(xí)慣的就是平常創(chuàng)建的TableView
更耻,我們都是將其添加在控制器的View
上,這里只是添加在UITableViewCell
上罷了捏膨,其他并無(wú)差異秧均。內(nèi)部實(shí)現(xiàn)說(shuō)到底其實(shí)就是充分利用UITableView
的特性,選取不同UITableViewCell
來(lái)顯示點(diǎn)贊列表
和評(píng)論列表
而已号涯,相比于方案一來(lái)說(shuō)目胡,該方案主要發(fā)揮出了UITableView
的特性,通過(guò)實(shí)現(xiàn)UITableView
的協(xié)議方法就能實(shí)現(xiàn)評(píng)論和點(diǎn)贊列表的展示诚隙,且實(shí)現(xiàn)起來(lái)更加簡(jiǎn)單易懂讶隐,這可能是目前市場(chǎng)上絕大多數(shù)的做法。雖然外表看似毫無(wú)破綻久又,但是其中隱藏巨大弊端巫延。之前筆者也利用這種方案效五,寫過(guò)類似微信朋友圈的評(píng)論回復(fù),詳情請(qǐng)參考:iOS 實(shí)現(xiàn)微信朋友圈評(píng)論回復(fù)功能(二)炉峰,但是其中存在的問(wèn)題畏妖,筆者卻沒(méi)有敘述,實(shí)屬抱歉疼阔,當(dāng)然這里筆者將詳述其存在弊端和產(chǎn)生的原因戒劫,以及讓大家重新加深對(duì)UITableView
的理解。弊端如下:-
復(fù)用問(wèn)題: 若想保證
UITableView
滾動(dòng)流暢婆廊,縱享絲滑迅细,就離不開UITableViewCell
的復(fù)用機(jī)制(PS:這個(gè)復(fù)用機(jī)制
想必大家應(yīng)該已經(jīng)滾瓜爛熟了,這里筆者就不在贅述)淘邻,這也是UITableView
的核心所在茵典。首先正常情況下,我們可以確定的是紅色框①
這個(gè)UITableViewCell
是能夠Cell復(fù)用
的宾舅,這個(gè)應(yīng)該是毫無(wú)爭(zhēng)議的统阿。但是紅色框①
內(nèi)部嵌套的綠色框②
這個(gè)TableView
中,其內(nèi)部顯示評(píng)論數(shù)據(jù)的UITableViewCell
是否也是支持Cell的復(fù)用機(jī)制
呢筹我?扶平??可能大家的第一印象就是覺(jué)得是能的蔬蕊。但是這里筆者強(qiáng)調(diào)的是綠色框②
中CommentCell
是不支持復(fù)用的=岢巍!袁串!大家認(rèn)為CommentCell
能夠復(fù)用
的概而,都是認(rèn)為其復(fù)用機(jī)制
完全跟紅色框①(MommentCell)
的復(fù)用機(jī)制
一樣,都是會(huì)隨著用戶滑動(dòng)的朋友圈列表囱修,MommentCell 和 CommentCell
離開都會(huì)完全離開屏幕赎瑰,然后將完全離開屏幕的MommentCell 和 CommentCell
存入緩存池,等到要顯示Cell
的時(shí)候又去緩存池根據(jù)reuseIdentifier
去取MommentCell 和 CommentCell
破镰,如果取得到餐曼,就直接拿來(lái)用;如果取不到鲜漩,就去創(chuàng)建等過(guò)程....源譬,這里筆者只能說(shuō)cell復(fù)用
的概念倒是背的的挺熟,但是Cell復(fù)用
的機(jī)制卻不夠理解孕似。原因是:* 之所以紅色框①
這個(gè)MomentCell
能夠遵循Cell復(fù)用
的機(jī)制踩娘,是因?yàn)槭紫绕渌幵诘?code>UITableView的尺寸大小是和屏幕尺寸大小一致,其次朋友圈列表能夠滑動(dòng)的前提就是保證該TableView
的內(nèi)容高度大于TableView
的高度喉祭,即tableView.contentSize.height > tableView.frame.size.height
养渴,需要強(qiáng)調(diào)的是:①Cell
能否產(chǎn)生復(fù)用
取決于所處的tableView
能否滾動(dòng)雷绢,②并且Cell
能夠隨著列表滾動(dòng)完全離開所處的TableView
的顯示范圍。結(jié)合這兩點(diǎn)必要條件理卑,很快可以推斷出紅色框①
這個(gè)UITableViewCell
是能夠滿足Cell復(fù)用
的條件的翘紊。接著我們帶著這兩個(gè)必要條件來(lái)分析一下綠色框②
這個(gè)TableView
,首先明確的是藐唠,該TableView
的高度是根據(jù)評(píng)論列表中每個(gè)評(píng)論內(nèi)容(CommentCell
)的高度總和(PS:tableView.height = cell0.height+cell1.height+cell2.height ...)帆疟,這樣就導(dǎo)致了該tableView
的內(nèi)容高度等于tableView
的尺寸高度,即(tableView.frame.size.height = tableView.contentSize.height
)宇立,所以評(píng)論列表是不會(huì)滾動(dòng)的踪宠,這樣就不滿足條件①;其次泄伪,其tableView
內(nèi)部的CommentCell
相對(duì)于所處的tableView
的顯示區(qū)域是完全暴露的殴蓬,根本不滿足條件②,所以最終真相大白蟋滴,水落石出了,是不是豁然開朗痘绎,心情舒暢津函。 當(dāng)然這里筆者友情提醒廣大開發(fā)者千萬(wàn)不要誤認(rèn)為,只要Cell
看不見(jiàn)就一定會(huì)產(chǎn)生復(fù)用
的誤區(qū)孤页,主要是要明確該Cell
相對(duì)于所處的TableView
的顯示區(qū)域是否看不見(jiàn)尔苦。(PS:知識(shí)點(diǎn)有木有),當(dāng)然大家可以跑跑筆者寫的這篇文章:iOS 實(shí)現(xiàn)微信朋友圈評(píng)論回復(fù)功能(二)所提供的Demo
行施,來(lái)驗(yàn)證一下筆者的這一說(shuō)法允坚。最后,如果綠色框②
這個(gè)TableView
一旦失去了Cell
的復(fù)用機(jī)制
蛾号,用腳趾頭想想也知道稠项,那造成的后果務(wù)必會(huì)重蹈方案一
存在的三個(gè)弊端的悲劇,這里筆者就不再贅述了鲜结,且筆者個(gè)人認(rèn)為整體性能還不如方案一
的展运。
-
復(fù)用問(wèn)題: 若想保證
-
方案三 【CoderMikeHe/WeChat】
該方案正是筆者目前使用的方案,該方案不僅很好的解決了方案一
和方案二
目前存在的弊端精刷,而且使用起來(lái)極其簡(jiǎn)單方便以及性能優(yōu)化上更是前兩個(gè)方案無(wú)法比擬的拗胜,當(dāng)然最主要的還是考察技巧性(黑魔法
)。首先筆者在認(rèn)定該方案之前怒允,前期筆者是做了大量的準(zhǔn)備工作埂软,以及仔細(xì)琢磨了紅色框①
(PS:類似一條說(shuō)說(shuō))這個(gè)整體的子模塊組成。當(dāng)然必須明確的是微信朋友圈的需求:綠色框②
能夠展示大量的評(píng)論數(shù)據(jù)(即:評(píng)論內(nèi)容列表的個(gè)數(shù)>=100 纫事,雖然我們會(huì)很少看到某個(gè)人的某條說(shuō)說(shuō)勘畔,有100多個(gè)人的評(píng)論內(nèi)容迷殿,而且微信的朋友圈信息流動(dòng)性非常快咖杂,這種大數(shù)據(jù)的產(chǎn)生會(huì)很少發(fā)生庆寺,但是這種大數(shù)據(jù)不代表沒(méi)有)。①考慮到微信朋友圈這一個(gè)硬需求诉字,筆者著重從性能上出發(fā)懦尝,第一想到的就是利用Cell的復(fù)用機(jī)制
來(lái)展示每條說(shuō)說(shuō)的評(píng)論內(nèi)容;②考慮到前兩個(gè)方案都是把紅色框①
當(dāng)做一個(gè)整體來(lái)處理壤圃,且都來(lái)了類似的弊端以及針對(duì)評(píng)論內(nèi)容大數(shù)據(jù)所帶來(lái)的性能問(wèn)題陵霉,以免重蹈覆轍,筆者將紅色框①
拆分為下圖幾個(gè)模塊:一條說(shuō)說(shuō)(紅色框①) = 組(段)頭(綠色框②) + Cell(紫色框③) + 組(段)尾(黑色框④)伍绳。
Moment_Plan3_UI.jpeg
通過(guò)上圖所示踊挠,雖然該方案在模塊劃分上是比較的分散,但是其總體帶來(lái)的性能是非吵迳保客觀的效床,大大保證了朋友圈列表滾動(dòng)的流暢性。其中當(dāng)然最最主要的原因還是歸功于上圖所示的組(段)頭(綠色框②)权谁、Cell(紫色框③)剩檀、組(段)尾(黑色框④)
這三個(gè)控件都是可以通過(guò)使用TableView
的數(shù)據(jù)源方法以及代理方法(代碼如下)輕松實(shí)現(xiàn)View的復(fù)用機(jī)制
的,而且都是平常開發(fā)中常用的方法旺芽,這樣前面兩個(gè)方案所存在的弊端就迎刃而解了沪猴。
/// UITableViewDelegate
/// 組(段)頭
- (nullable UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section;
/// 組(段)尾
- (nullable UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section;
/// UITableViewDataSource
/// Cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
當(dāng)然采章,組(段)頭运嗜、組(段)尾
的內(nèi)部控件布局,想必對(duì)于大家已經(jīng)是手到擒來(lái)的東西悯舟,這里筆者也不過(guò)多討論担租,詳情請(qǐng)參考筆者提供的Demo
,自行領(lǐng)會(huì)图谷。這里筆者主要想說(shuō)的就是Cell(紫色框③)
翩活,首先平常開發(fā)過(guò)程中,Cell
的寬度一般是跟所處的tableView
的寬度是一致的便贵,但是微信朋友圈里面的這個(gè)評(píng)論Cell
明顯不是菠镇,這里筆者需要強(qiáng)調(diào)的是:重寫是個(gè)好東西。這里的關(guān)鍵點(diǎn)就是在于重寫自定義的UITableViewCell
的- (void)setFrame:(CGRect)frame
方法承璃,關(guān)鍵代碼如下:
/// PS:重寫cell的設(shè)置尺寸的方法利耍, 這是評(píng)論View關(guān)鍵
- (void)setFrame:(CGRect)frame{
frame.origin.x = MHMomentContentLeftOrRightInset+MHMomentAvatarWH+MHMomentContentInnerMargin;
frame.size.width = MHMomentCommentViewWidth();
[super setFrame:frame];
}
當(dāng)然對(duì)于這種方案(組(段)頭+Cell+組(段)尾
)的實(shí)現(xiàn)過(guò)程,筆者以前就寫過(guò)一篇文章,來(lái)詳細(xì)介紹這其中的關(guān)鍵點(diǎn)隘梨,詳情請(qǐng)參考:iOS 實(shí)現(xiàn)微信朋友圈評(píng)論回復(fù)功能(一)程癌。最后,筆者個(gè)人認(rèn)為這個(gè)方案目前是實(shí)現(xiàn)類似微信朋友圈這種支持無(wú)限評(píng)論需求的最優(yōu)雅的實(shí)施方案轴猎。
當(dāng)然還有一種方案就是:微信官方團(tuán)隊(duì)做朋友圈開發(fā)的實(shí)現(xiàn)方案嵌莉。如果這篇文章能夠有幸被微信的開發(fā)人員看到,也請(qǐng)微信的開發(fā)人員分享一下微信官方的朋友圈的實(shí)現(xiàn)方案哦捻脖;或者如果筆者的這個(gè)方案正好和微信官方的如出一轍锐峭,那么也請(qǐng)為筆者瘋狂打Call
(權(quán)威認(rèn)證)哦。最后筆者希望這篇文章能夠?yàn)榇蠹医獬┰S疑惑可婶,帶來(lái)些許幫助沿癞。
功能
分析開發(fā)筆者在微信朋友圈時(shí)多遇到一些比較需要技巧性的功能模塊的實(shí)現(xiàn)以及細(xì)節(jié)處理,當(dāng)然實(shí)現(xiàn)的方案一定不是唯一的矛渴,但是筆者的目的是希望大家能夠積極討論椎扬,然后繼續(xù)完善朋友圈的各個(gè)功能模塊。
-
評(píng)論/回復(fù)時(shí)具温,
TableView
滾動(dòng)到指定的區(qū)域
這個(gè)功能是目前小伙伴問(wèn)的最多的小功能模塊之一蚕涤,具體效果圖如下所示(PS:打開自己手機(jī)中微信朋友圈,玩弄一下):首先我們的明確該功能主要是為了避免鍵盤
和評(píng)論輸入框
遮蓋住用戶想要評(píng)論或回復(fù)的內(nèi)容桂躏。其次微信朋友圈官方做法(需求)是:① 用戶點(diǎn)擊組(段)頭(綠色框②)
上的彈出的【評(píng)論】按鈕 钻趋, 彈出鍵盤
和評(píng)論輸入框
,我們需要保證組(段)尾(黑色框④)
的底部顯示在評(píng)論輸入框
的頂部剂习,且伴隨著評(píng)論輸入框
高度的變化而組(段)尾(黑色框④)
的底部仍舊顯示在評(píng)論輸入框
的頂部; ② 用戶點(diǎn)擊評(píng)論Cell(紫色框③)
彈出鍵盤
和評(píng)論輸入框
较沪,我們需要保證評(píng)論Cell(紫色框③)
的底部顯示在評(píng)論輸入框
的頂部鳞绕,且伴隨著評(píng)論輸入框
高度的變化而評(píng)論Cell(紫色框③)
的底部仍舊顯示在評(píng)論輸入框
的頂部;
Comment.gif
經(jīng)過(guò)上述的需求分析尸曼,我們可以明確的是:當(dāng)彈出鍵盤
和評(píng)論輸入框
時(shí)们何,滾動(dòng)TableView
到合適的區(qū)域來(lái)滿足上述的條件即可,滾動(dòng)TableView
無(wú)非就是設(shè)置其contentOffset.y
(PS:- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated
)的值即可控轿,目前最關(guān)鍵的就是計(jì)算出:需要計(jì)算出contentOffset.y
的值即可冤竹。
筆者僅以上面的需求①
為例,來(lái)說(shuō)說(shuō)筆者的思路和做法茬射,首先如果彈出鍵盤
和評(píng)論輸入框
時(shí)鹦蠕,TableView
不設(shè)置合適contentOffset
,則UI效果無(wú)非是以下三種情況:(PS:紅色分割線代表鍵盤
和評(píng)論輸入框
彈出時(shí)在抛,評(píng)論輸入框
的頂部所處的位置 钟病, 其他顏色的分割線代表組(段)尾(黑色框④)
的底部位置)
場(chǎng)景一 | 場(chǎng)景二 | 場(chǎng)景三 |
---|---|---|
Moment_UI_Up.png
|
Moment_UI_NO.png
|
Moment_UI_Down.png
|
delta = Y1 - Y2 < 0 |
delta = Y1 - Y2 = 0 |
delta = Y1 - Y2 > 0 |
場(chǎng)景一:該情況如果不設(shè)置TableView
滾動(dòng),那么勢(shì)必會(huì)導(dǎo)致鍵盤
和評(píng)論輸入框
遮蓋住評(píng)論內(nèi)容(PS:藍(lán)色分割線),從而影響用戶體驗(yàn)肠阱;如果想要顯示出評(píng)論內(nèi)容票唆,只需要讓TableView
向上(delta < 0
)滾動(dòng)abs(Delta)
距離。
場(chǎng)景二: 該情況屬于理想狀態(tài)屹徘,TableView
無(wú)需上下滾動(dòng)走趋。
場(chǎng)景三:該情況若不處理,則會(huì)導(dǎo)致要評(píng)論的內(nèi)容噪伊,距離評(píng)論輸入框
很遠(yuǎn)簿煌,會(huì)讓用戶懷疑這條評(píng)論究竟是評(píng)論誰(shuí)的,從而影響用戶體驗(yàn)酥宴。為了達(dá)到需求啦吧,則需要讓TableView
向下(delta > 0
)滾動(dòng)Delta
距離即可。
想必通過(guò)上表的畫圖分析拙寡,想必大家已經(jīng)胸有成竹了吧授滓。目前最主要的是:如何計(jì)算出Delta = Y1 - Y2
的值?
首先我們應(yīng)該知道,評(píng)論輸入框
和組(段)尾(黑色框④)
處于不同的坐標(biāo)系肆糕,不能直接計(jì)算般堆,所以,關(guān)鍵點(diǎn)就是我們必須將組(段)尾(黑色框④)
的坐標(biāo)系轉(zhuǎn)換成和評(píng)論輸入框
一樣的坐標(biāo)系诚啃,其次再設(shè)置TableView
的contentOffset.y = contentOffset.y + delta
即可淮摔。需求②也采用類似的方法來(lái)處理即可,這里筆者不再贅述始赎,詳情見(jiàn)Demo和橙,關(guān)鍵代碼如下所示:
/// 評(píng)論的時(shí)候 滾動(dòng)tableView
- (void)_scrollTheTableViewForComment{
CGRect rect = CGRectZero;
CGRect rect1 = CGRectZero;
if (self.selectedIndexPath.row == -1) {
/// 獲取整個(gè)尾部section對(duì)應(yīng)的尺寸 獲取的rect是相當(dāng)于tableView的尺寸
rect = [self.tableView rectForFooterInSection:self.selectedIndexPath.section];
/// 將尺寸轉(zhuǎn)化到window的坐標(biāo)系 (關(guān)鍵點(diǎn))
rect1 = [self.tableView convertRect:rect toViewOrWindow:nil];
}else{
/// 回復(fù)
/// 獲取整個(gè)尾部section對(duì)應(yīng)的尺寸 獲取的rect是相當(dāng)于tableView的尺寸
rect = [self.tableView rectForRowAtIndexPath:self.selectedIndexPath];
/// 將尺寸轉(zhuǎn)化到window的坐標(biāo)系 (關(guān)鍵點(diǎn))
rect1 = [self.tableView convertRect:rect toViewOrWindow:nil];
}
if (self.keyboardHeight > 0) { /// 鍵盤抬起 才允許滾動(dòng)
/// 這個(gè)就是你需要滾動(dòng)差值
CGFloat delta = self.commentToolView.mh_top - rect1.origin.y - rect1.size.height;
[self.tableView setContentOffset:CGPointMake(0, self.tableView.contentOffset.y-delta) animated:NO];
}
}
未完...待續(xù)...(PS:不說(shuō)再見(jiàn),我們后會(huì)有期)
本篇文章筆者主要是分析實(shí)現(xiàn)微信朋友圈的最優(yōu)方案造垛,希望能為大家在敲代碼之前樹立一個(gè)正確的參考魔招,這樣能夠避免大家走許多彎路。當(dāng)然微信朋友圈的技術(shù)要點(diǎn)和技術(shù)細(xì)節(jié)五辽,雖然看似簡(jiǎn)單办斑,但是細(xì)節(jié)處理非常重要,筆者在接下來(lái)的時(shí)間內(nèi)杆逗,會(huì)陸續(xù)為其增加更多功能模塊乡翅,以及將在開發(fā)WeChat
朋友圈中用到的好用技術(shù)以及細(xì)節(jié)處理分享出來(lái),希望提供大家一個(gè)參考罪郊,爭(zhēng)取能為大家答疑解惑蠕蚜。當(dāng)然也希望大家踴躍發(fā)言,共同交流排龄,共同進(jìn)步波势。
期待
- 文章若對(duì)您有些許幫助翎朱,請(qǐng)給個(gè)喜歡??,畢竟碼字不易尺铣;若對(duì)您沒(méi)啥幫助拴曲,請(qǐng)給點(diǎn)建議??,切記學(xué)無(wú)止境凛忿。
- 針對(duì)文章所述內(nèi)容澈灼,閱讀期間任何疑問(wèn);請(qǐng)?jiān)谖恼碌撞吭u(píng)論指出店溢,我會(huì)火速解決和修正問(wèn)題叁熔。
- GitHub地址:https://github.com/CoderMikeHe
- 源碼地址:WeChat