Swift开发iOSiOS之设计模式

iOS 基于MVVM设计模式的微信朋友圈开发

2018-01-19  本文已影响2630人  CoderMikeHe
前言
分析

前期在敲代码之前,需要着重分析一下整个微信朋友圈界面的实现方案,这可能是本篇文章的核心所在了(PS:这里特别提醒一下广大开发者,在实现某一个功能前,请务必确定一个实现方案,可能实现的方案千千万,这就需要开发者通过自身的理解来确定一个最优的方案来实现,而不是一昧毫无头绪的敲代码,造成后期又得重新迭代的悲剧!!!)。微信朋友圈的效果图如下(PS:万恶的马赛克...)。


Moment.jpeg

当然整体的界面的布局还是比较复杂的,前期看了UI还是挺让人望而却步的。首先,我们可以确定的是整体是利用UITableView来实现的,是不是大家已经隐隐约约感受到还是原来的配方,还是熟悉的味道,相同的tableView,变得只是Cell罢了。其次,笔者经过多日在GitHub上搜寻一些实现微信朋友圈的开发的Demo,以及做了大量的市场调研和内容对比,发现最具代表性的两个Demo分别是:gsdios/GSD_WeiXinzhengwenming/WeChat,其他Demo大多数都是参考这两个Demo来做的,当然这两个Demo实现微信朋友圈的方法涉及到两个不同的方案,笔者就带大家简单分析一下各自的方案实现过程以及目前存在的弊端(PS:这里所谓的弊端,只是针对微信朋友圈而言的)。两者的界面模块划分如下(PS: ① 红色框 , ②:绿色框):

Moment_UI.jpeg
当然这两个Demo的实现朋友圈的 共同之处就是:将图上所示的红框①整体用一个UITableViewCell来展示。不同之处 就是:图上所示的绿框②的控件选取不同罢了。
UITableViewCell上布局子控件相对于大家肯定是小菜一碟,这里笔者就针对两个Demo绿框②的控件的选取上做文章以及分析其目前存在的弊端。当然这两个方案目前都不是最最优化的方案,通过分析其中存在弊端,逐渐引申出比较令人合理的方案,当然笔者最终会给出自己的方案,但也许未必是最优的方案,更好的方案或许就存在大家的手中,笔者这里主要强调的是 知其然,知其所以然。话不多说,Let's Do It!

通过上图所示,虽然该方案在模块划分上是比较的分散,但是其总体带来的性能是非常客观的,大大保证了朋友圈列表滚动的流畅性。其中当然最最主要的原因还是归功于上图所示的组(段)头(绿色框②)、Cell(紫色框③)、组(段)尾(黑色框④)这三个控件都是可以通过使用TableView的数据源方法以及代理方法(代码如下)轻松实现View的复用机制的,而且都是平常开发中常用的方法,这样前面两个方案所存在的弊端就迎刃而解了。

/// 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;

当然,组(段)头、组(段)尾的内部控件布局,想必对于大家已经是手到擒来的东西,这里笔者也不过多讨论,详情请参考笔者提供的Demo,自行领会。这里笔者主要想说的就是Cell(紫色框③),首先平常开发过程中,Cell的宽度一般是跟所处的tableView的宽度是一致的,但是微信朋友圈里面的这个评论Cell明显不是,这里笔者需要强调的是:重写是个好东西。这里的关键点就是在于重写自定义的UITableViewCell- (void)setFrame:(CGRect)frame方法,关键代码如下:

/// PS:重写cell的设置尺寸的方法, 这是评论View关键
- (void)setFrame:(CGRect)frame{
    frame.origin.x = MHMomentContentLeftOrRightInset+MHMomentAvatarWH+MHMomentContentInnerMargin;
    frame.size.width = MHMomentCommentViewWidth();
    [super setFrame:frame];
}

当然对于这种方案(组(段)头+Cell+组(段)尾)的实现过程,笔者以前就写过一篇文章,来详细介绍这其中的关键点,详情请参考:iOS 实现微信朋友圈评论回复功能(一)。最后,笔者个人认为这个方案目前是实现类似微信朋友圈这种支持无限评论需求的最优雅的实施方案。
当然还有一种方案就是:微信官方团队做朋友圈开发的实现方案。如果这篇文章能够有幸被微信的开发人员看到,也请微信的开发人员分享一下微信官方的朋友圈的实现方案哦;或者如果笔者的这个方案正好和微信官方的如出一辙,那么也请为笔者疯狂打Call(权威认证)哦。最后笔者希望这篇文章能够为大家解除些许疑惑,带来些许帮助。

功能

分析开发笔者在微信朋友圈时多遇到一些比较需要技巧性的功能模块的实现以及细节处理,当然实现的方案一定不是唯一的,但是笔者的目的是希望大家能够积极讨论,然后继续完善朋友圈的各个功能模块。

场景一 场景二 场景三
Moment_UI_Up.png Moment_UI_NO.png Moment_UI_Down.png
delta = Y1 - Y2 < 0 delta = Y1 - Y2 = 0 delta = Y1 - Y2 > 0

场景一:该情况如果不设置TableView滚动,那么势必会导致键盘评论输入框遮盖住评论内容(PS:蓝色分割线),从而影响用户体验;如果想要显示出评论内容,只需要让TableView向上(delta < 0)滚动abs(Delta)距离。
场景二: 该情况属于理想状态,TableView无需上下滚动。
场景三:该情况若不处理,则会导致要评论的内容,距离评论输入框很远,会让用户怀疑这条评论究竟是评论谁的,从而影响用户体验。为了达到需求,则需要让TableView向下(delta > 0)滚动Delta距离即可。
想必通过上表的画图分析,想必大家已经胸有成竹了吧。目前最主要的是:如何计算出Delta = Y1 - Y2的值?
首先我们应该知道,评论输入框组(段)尾(黑色框④)处于不同的坐标系,不能直接计算,所以,关键点就是我们必须将组(段)尾(黑色框④)的坐标系转换成和评论输入框一样的坐标系,其次再设置TableViewcontentOffset.y = contentOffset.y + delta即可。需求②也采用类似的方法来处理即可,这里笔者不再赘述,详情见Demo,关键代码如下所示:

/// 评论的时候 滚动tableView
- (void)_scrollTheTableViewForComment{
    CGRect rect = CGRectZero;
    CGRect rect1 = CGRectZero;
    if (self.selectedIndexPath.row == -1) {
        /// 获取整个尾部section对应的尺寸 获取的rect是相当于tableView的尺寸
        rect = [self.tableView rectForFooterInSection:self.selectedIndexPath.section];
        /// 将尺寸转化到window的坐标系 (关键点)
        rect1 = [self.tableView convertRect:rect toViewOrWindow:nil];
    }else{
        /// 回复
        /// 获取整个尾部section对应的尺寸 获取的rect是相当于tableView的尺寸
        rect = [self.tableView rectForRowAtIndexPath:self.selectedIndexPath];
        /// 将尺寸转化到window的坐标系 (关键点)
        rect1 = [self.tableView convertRect:rect toViewOrWindow:nil];
    }
    if (self.keyboardHeight > 0) { /// 键盘抬起 才允许滚动
        /// 这个就是你需要滚动差值
        CGFloat delta = self.commentToolView.mh_top - rect1.origin.y - rect1.size.height;
        [self.tableView setContentOffset:CGPointMake(0, self.tableView.contentOffset.y-delta) animated:NO];
    }
}
未完...待续...(PS:不说再见,我们后会有期)

本篇文章笔者主要是分析实现微信朋友圈的最优方案,希望能为大家在敲代码之前树立一个正确的参考,这样能够避免大家走许多弯路。当然微信朋友圈的技术要点和技术细节,虽然看似简单,但是细节处理非常重要,笔者在接下来的时间内,会陆续为其增加更多功能模块,以及将在开发WeChat朋友圈中用到的好用技术以及细节处理分享出来,希望提供大家一个参考,争取能为大家答疑解惑。当然也希望大家踊跃发言,共同交流,共同进步。

期待
  1. 文章若对您有些许帮助,请给个喜欢❤️,毕竟码字不易;若对您没啥帮助,请给点建议💗,切记学无止境。
  2. 针对文章所述内容,阅读期间任何疑问;请在文章底部评论指出,我会火速解决和修正问题。
  3. GitHub地址:https://github.com/CoderMikeHe
  4. 源码地址:WeChat
参考链接
上一篇下一篇

猜你喜欢

热点阅读