点击上方“程序员一起读”,选择“置顶公众号”
关键时刻送达!
前言
分析
在写代码之前,需要分析整个微信朋友圈界面的实现方案,这或许就是本文的核心了(PS:这里特别提醒开发者,在实现某个功能之前,请务必确定一个实现方案,可能的实现方案有千万种,这就需要开发者通过自己的理解来确定最佳方案,而不是盲目的写代码,没有任何头绪,导致后期又要重新迭代的悲剧!!!)。微信朋友圈效果图如下(PS:邪恶的马赛克……)。
.jpeg
当然,整体的界面布局还是比较复杂的,前期UI还是比较让人望而生畏的。首先我们可以肯定整体的设计是使用 来实现的。大家是否已经隐约感觉到还是原来的配方,熟悉的味道,千篇一律,只不过变成了一个Cell而已。其次,经过很多天在网上搜索一些实现微信朋友圈开发的Demo,并且做了大量的市场调研和内容对比,我发现最有代表性的两个Demo就是: 和 。其他的Demo大部分都是参考这两个Demo做的。当然这两个Demo中实现微信朋友圈的方法涉及到了两种不同的方案,笔者就带大家简单分析一下各个方案的实现过程以及目前存在的弊端(PS:这里所谓的弊端只是针对微信朋友圈而言的)。两者的界面模块划分如下(PS:①红色框,②:绿色框):
.jpeg
当然这两个demo在实现朋友圈的共同点就是图中所示的红色框①是整体展示的,不同之处在于图中所示的绿色框②的控件选择方式不同。
子控件的布局对于大家来说肯定是小菜一碟,这里我会重点针对两个demo中绿色框②中的控件选择,分析其目前的弊端。当然这两种方案都不是目前最优化的方案,通过分析弊端,逐渐得出更加合理的方案。当然,作者最终会给出自己的解决方案,但未必是最好的方案,更好的方案也许存在于大家的手中。作者这里主要强调的是,知其然,知其所以然。废话不多说,Let's Do It!
复杂布局:考虑到绿色框②内部子控件布局的复杂性,作者采用自己的代码来实现,作者对此并不是很熟悉,关于其布局代码的实现请关注其Demo的.h/m文件。虽然其内部布局代码看上去简单,但如果我们不使用它,那么传统的布局还是相当复杂的。比如我们要计算红色框①()的高度,就需要先计算绿色框②内部所有子控件的大小(),从而推导出绿色框②的整体高度,最终确定红色框①()的高度。作者猜测作者可能主要在这里是为了凸显自动布局的强大和便捷,如同项庄舞剑,瞄准裴公。
动态创建:我们知道红框①()是支持复用的,这是毋庸置疑的,但是我们知道每篇帖子(红框①)包含的评论列表数量是不一样的,cell高度也是不一样的。这样就会涉及到当用户滚动朋友圈列表,cell被复用时,绿框②里面的子控件数量也是动态的,可能增多也可能减少,从而导致绿框②里面的子控件动态增删。相信大家都知道最好不要在 中动态创建子控件,这样比较耗性能。常规的做法是,在 -():():( *) 中,一次性把想要显示的控件全部创建好,这样只需要根据数据的属性显示或者隐藏某个子控件,就避免了动态创建子控件的场景。但是由于朋友圈列表每篇帖子的评论列表数量无法提前确定,因此难免会出现在绿框②中动态创建子控件的悲剧。
不支持大数据:关于上面动态创建控件的问题,作者其实对.h/m内部是有优化的,主要做法是把动态创建的子控件()放到一个数组()里,这样可以减少一部分动态创建子控件。但是还是会有动态创建子控件的情况,主要逻辑就是比较你传入的评论列表中的评论数(.)和.,如果前者小于等于后者,就不需要动态创建,只需要显示并隐藏里面的子控件即可;反之,如果前者大于后者,就需要动态创建(.-.)子控件,然后添加到数组里即可。关键代码如下:首先微信朋友圈的评论数是支持大数据的(PS:是我猜的。。。),所以需要保证绿色框②能支持大数据的显示。 显然,随着评论列表数量逐渐增多并被不断复用,绿色框②中的子控件数量也会随之增加,并保持增加的趋势,因此这种方案显得比较弱。
- (空白):( *){
=;
长 = .;
长 = . > ? (.- ) : 0;
对于(int i = 0; i <; i++){
* = [新];
[自己 :];
[ :];
以上是我在[ ]中发现的一些问题以及个人的理解。当然,这种方案在处理大量评论数据时可能会有些困难,但如果评论列表数量是固定的,例如:优酷视频的评论回复(如下图)。这种方案也是很好的解决方案。因此,不同的业务场景有不同的实施方案。可见在敲代码之前思考和确定实施方案是多么重要。
.png
复用问题:想要保证滚动流畅,享受流畅,就离不开复用机制(PS:这个复用机制相信大家应该很熟悉,这里就不再赘述了),这也是核心。首先正常情况下我们可以肯定红框①是可以复用Cell的,这应该是毫无争议的。但是在红框①里面嵌套的绿框②,是否也支持显示评论数据的Cell的复用机制呢???可能大家的第一印象是可以。但这里作者要强调的是,绿框②是不支持复用的!!! 那些认为可以复用的都认为,它们的复用机制和红框①()一模一样,即随着用户在好友列表的滑动, 会完全离开屏幕,此时完全离开屏幕的 会存放到缓存池中,当该Cell要显示时,再去缓存池中获取 ,如果获取到了,则直接使用;如果没有,则再创建等等……这里笔者只能说,对于Cell复用这个概念比较熟悉,但是对于Cell复用的机制还不是很理解。
原因是: * 红色框①之所以能遵循Cell复用的机制,首先cell的size和屏幕尺寸一致,其次朋友圈列表滑动的前提是保证内容高度大于cell高度,即.. > ..size。需要强调的是:①cell能否复用取决于cell能否滚动,②cell能随着列表滚动完全离开cell的显示范围。结合这两个必要条件,可以很快推断出红色框①能满足Cell复用的条件。接下来我们结合这两个必要条件来分析绿色框②。 首先很显然,cell的高度是根据评论列表中每条评论内容的高度之和(PS:.=.+.+....),这就导致内容的高度等于size高度,也就是(..size.=..),所以评论列表不会滚动,不满足条件①;其次,内部相对于显示区域是完全露出来,完全不满足条件②,所以最后真相大白,真相大白,是不是豁然开朗,心旷神怡呢?
当然这里要提醒各位开发者,千万不要误以为只要cell不可见就一定会被复用,最主要的还是要明确cell相对于显示区域是否不可见。(PS:还有知识点吗?),当然大家可以运行我写的这篇文章:iOS实现微信朋友圈评论回复功能(二)()提供的demo来验证我的说法。最后,如果绿色框②失去了cell复用机制,大家可以用脚趾头去想一想,其后果一定会重演方案一的三个弊端的悲剧,这里就不细说了,个人认为整体性能不如方案一。
.jpeg
如上图所示,虽然这个方案的模块划分比较散乱,但是它的整体表现还是很客观的,极大的保证了朋友圈列表滚动的流畅度。当然,最主要的原因还是上图所示的三个控件,即()(绿色框②)、Cell(紫色框③)、()(黑色框④),可以通过使用数据源方法和代理方法(代码如下)很方便的实现View的复用机制,而这些在日常开发中都是很常用的方法,所以解决了前面两个方案的弊端。
///
/// 组(段)标题
- ( *):( *) 在:();
/// 组(段)结束
- ( *):( *) 在:();
/// 电子
/// 细胞
- ( *):( *) H:( *);
当然,()和()内部控件的布局想必大家都已经掌握了,这里就不做过多讨论了,具体可以参考作者提供的demo,自己去理解。这里作者主要想说一下Cell(紫色框③)。首先,在正常的开发过程中,Cell的宽度一般都是和单元格的宽度保持一致的,但是微信朋友圈里的这个注释Cell显然不是。这里需要强调的是,重写是个好东西,这里重点就是重写自定义的-(void):()方法,关键代码如下:
/// PS:重写设置cell大小的方法,这个是注释View的关键
- (空白):(){
..x = ++;
.大小。 = idth();
[ :];
当然,对于这个方案(()+Cell+()tail)的实现过程,笔者之前已经写过一篇文章详细介绍过其中的要点,具体可以参考:iOS实现微信朋友圈评论回复功能(一)()。最后,笔者个人认为,这个方案是目前实现像微信朋友圈一样支持无限评论的需求,最优雅的实现方案。
当然还有另一种解决方案:微信官方团队为朋友圈开发了解决方案。如果这篇文章有幸被微信开发者看到,请将微信朋友圈官方解决方案分享给他们;或者我的解决方案和微信官方一模一样,请点个赞(权威认证)。最后希望这篇文章能帮大家解决一些疑惑,带来一些帮助。
未完待续……(PS:没有再见,我们还会再见)
在本文中,笔者主要分析了实现微信朋友圈的最优方案,希望给大家在敲代码之前提供一个正确的参考,避免走很多弯路。当然,微信朋友圈的技术点和技术细节虽然看似简单,但细节很重要。在接下来的一段时间里,笔者会逐步为其添加更多的功能模块,并将朋友圈开发中用到的有用的技术和细节分享出来,希望给大家提供一个参考,争取解答大家的疑问。当然也希望大家积极发言,一起交流,共同进步。
预计
如果文章对你有些帮助,请点个赞❤️,毕竟写作不容易;如果对你没帮助,还请给点建议,记住学习永无止境。
如果对本文内容有任何疑问,请在文章底部留言,我会尽快解决并纠正问题。
地址:
源代码地址:
参考链接