美文网首页iOS 实用技术demo程序员
iOS 实现微信朋友圈评论回复功能(一)

iOS 实现微信朋友圈评论回复功能(一)

作者: CoderMikeHe | 来源:发表于2017-02-13 12:57 被阅读10277次
一、概述
  • iOS开发中,相信许多开发者都遇到过,类似于像微信朋友圈的评论回复功能的开发,难点莫过于 Cell里面的子控件布局点击事件的回调评论回复的逻辑处理
  • 笔者将通过 两种方法来实现微信朋友圈评论回复功能,也将通过一个仿优酷视频评论和回复的Demo 来实战一番,本文将通过利用UITableView段头+cell+段尾来实现,希望能为广大开发者提供一点思路,少走一些弯路,填补一些细坑。
  • iOS实现微信朋友圈评论回复功能(二)
  • iOS 实现优酷视频的评论回复功能

二 、 效果图


效果图.gif
三、利用UITableView段头+cell+段尾实现
  1. 页面分析
  1. 技术分析
  • 列表展示数据流
    • 列表通常利用tableView来实现。
    • tableview实现又分为自动布局绝对布局(即Frame布局
      自动布局:个人推荐利用Masonry+UITableView-FDTemplateLayoutCell的方案来实现自动布局。
      Frame布局: 事先计算出Cell子控件的Frame以及Cell的高度,存入ModelFrame里面,虽然计算稍微复杂,但是性能好,可控性强,易动画,扩展维护成本低
      两种布局方式不是本文的重点,依旧个人喜好,笔者偏好是Frame布局,本文案例也将采用这种方式。
  • Cell里面的昵称支持点击跳转用户信息
    • 首先明确内容支持 attributedString(富文本)而不是text(普通文本)
    • 可以使用 UILabelattributedText,或者采用第三方框架TYAttributedLabelYYText,笔者在此采用的是YYText
3. 技术难点
  • Frame布局计算复杂

    1. 实际项目中,我们从服务器获取的数据,转换为数据模型(Model),对应的数据有些不能直接显示在视图(View)上,需要二次处理。tableviewCell高度计算,是tableView使用以及优化的重点对象,最好的方式莫过于高度缓存,笔者这里为每个模型(Model)配备一个模型尺寸(ModelFrame),主要用来计算tableViewCell的高度(cellHeight),以及子控件的尺寸(frame),而且保证模型(Model)的纯净性以及减少胖模型的生成。
    2. ModelFrame模型持有Model,并开放cell中各个子控件的Frame属性,,以及cellHeight缓存cell高度。注意:这里属性应该设置为readonly来修饰更为合理,防止外界修改对应的尺寸(Frame),切记:细节显能力
    3. 重写ModelFrameModelsetter方法,计算tabelViewCellheaderView子控件的Frame以及缓存cell的高度cellHeightheaderView的高度height
    4. tableViewCellheaderView自身持有各自ModelFrame模型,在tableView的数据源给tableViewCellCellheaderView注入ModelFrame时,确定tabelViewCellheaderView的子控件的布局(Frame)以及数据。
  • Cell宽度的修改
    只要重写tableViewCellframesetter方法即可统一修改cell的尺寸。

     - (void)setFrame:(CGRect)frame
     {
           frame.origin.x = MHVideoTopicAvatarWH+2*MHVideoTopicHorizontalSpace;
           frame.size.width = MHMainScreenWidth - frame.origin.x - MHVideoTopicHorizontalSpace;
           [super setFrame:frame];
      }
    
  • 复杂的事件回调
    事件传递三种方式delegatenotificationblock。笔者项目采用的是代理delegate,将所有事件代理给viewController,事件的传递详情,请查看文章下方给出的Demo地址。

四、细节处理
  1. 设置文本的额外区域,防止文字过少,用户无法点中文本的bug
    Label的额外区域@2x.png
  // 文本
  YYLabel *contentLabel = [[YYLabel alloc] init];

  // 设置文本的额外区域,修复用户点击文本没有效果
  UIEdgeInsets textContainerInset = contentLabel.textContainerInset;
  textContainerInset.top = MHVideoTopicVerticalSpace;
  textContainerInset.bottom = MHVideoTopicVerticalSpace;
  contentLabel.textContainerInset = textContainerInset;
  
  contentLabel.numberOfLines = 0 ;
  contentLabel.textAlignment = NSTextAlignmentLeft;
  [self.contentView addSubview:contentLabel];
  1. 点击评论昵称获取用户模型(MHUser
  • 点击评论昵称,在评论模型(MHComment)中通过通知传递用户模型(MHUser)。虽获取用户模型(MHUser)简单,但使用通知会增加项目的耦合性
// 文本高亮模型
      YYTextHighlight *toUserHighlight = [YYTextHighlight highlightWithBackgroundColor:[UIColor colorWithWhite:0.000 alpha:0.220]];
      // 这里痛过属性的userInfo保存User模型,后期通过获取模型然后获取User模型
      toUserHighlight.userInfo = @{MHCommentUserKey:self.toUser};
      
      // 点击用户的昵称的事件传递
//        toUserHighlight.tapAction = ^(UIView *containerView, NSAttributedString *text, NSRange range, CGRect rect)
//        {
//            // 这里通过通知把用户的模型传递出去
//        };
  • 点击评论昵称,通过label的点击事件来获取,由于YYLablehighlightTapAction的事件,无法获取YYTextHighlight模型,但是通过KVC可以获取到YYTextHighlight模型,从而得到textHighlight.userInfo。这样一来通过delegate就可将用户模型(MHUser)传递出去。
__weak typeof(self) weakSelf = self;
    contentLabel.highlightTapAction = ^(UIView *containerView, NSAttributedString *text, NSRange range, CGRect rect) {
        
        // 利用KVC获取UserInfo 其实可以在MHComment模型里面利用 通知告知控制器哪个用户被点击了
        YYTextHighlight *highlight = [containerView valueForKeyPath:@"_highlight"];
        
        if (weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(commentCell:didClickedUser:)]) {
            [weakSelf.delegate commentCell:weakSelf didClickedUser:highlight.userInfo[MHCommentUserKey]];
        }       
    };
五、期待
  1. 文章若对您有点帮助,请给个喜欢❤️,毕竟码字不易;若对您没啥帮助,请给点建议💗,切记学无止境。
  2. 针对文章所述内容,阅读期间任何疑问;请在文章底部评论指出,我会火速解决和修正问题。
  3. GitHub地址:https://github.com/CoderMikeHe
六、代码

MHDevelopExample_Objective_C - MHTopicOneController.h/m

相关文章

网友评论

  • 魏志军:点击评论后想让tableview上移,cell不被遮挡
  • 蒲公英守候_c082:老哥,这个github下载下来的,为什么pod文件没有,也pod不进去,麻烦你能看看不
    CoderMikeHe:@蒲公英守候_c082 将 CMHDEBUG 这个宏改成 0 即可
    蒲公英守候_c082:百度云的下载了,只是没找到,朋友圈评论这个demo
    CoderMikeHe:@蒲公英守候_c082 有百度云,详见ReadMe
  • JYou:大神你好,最近公司要快速开发一个即时通讯app,看了一些方案,觉得您的仿微信demo很不错,但整体demo过于复杂,请问下有单独朋友圈的demo分享吗?谢谢
  • ZhangCc_:一个section里,都用cell会有问题吗?
    CoderMikeHe:@ZhangCc_ :blush:
    ZhangCc_:@CoderMikeHe :smile: :blush: :kissing_heart:
    CoderMikeHe:@ZhangCc_ 稳如藏獒。:+1:
  • 呃哈哈:你好,我对ReactiveCocoa不是很熟,我想删除其中某一个MHMomentItemViewModel,但是NSArray不可修改。我看到你备注的NSMutableArray不支持KVO,不能被RACObserve。所以有什么好的建议吗
  • ad3fd5aca069:新人学习,请教下几个问题
    这整个一块(段头 + cell + 段尾)是一个大的cell吧,然后里面的小cell应该是又是一个tableView列表,但这样的话不就是方案二吗(cell 里面嵌套tableView),所以猜测这整个一块难道就是一个tableView,然后内容就是组头+内容+组尾的方式,那这样的话这一个列表得多少个tableView,糊涂了,请教下大神
    CoderMikeHe:@bls 你理解错误了呢! 整个一块是由`组头+ 回复cell+组尾`组成,而不是你所谓的一个自定义的大cell 。这里的Cell只是单纯用来显示评论或回复数据。百度网盘地址私发给你了。
    ad3fd5aca069:@CoderMikeHe demo下载失败,这三个方法我知道,我的意思是,你这整个一块是一个自定义的大cell ,大cell里面的布局有组头+ 回复cell+组尾(这不就是一个tableView么),那现在列表有100条数据,就是有100个大cell,那每个大cell里面不就是都有一个(组头+ 回复cell+组尾即一个tableView),我是这么理解的
    CoderMikeHe:@bls 没有呀,先看看Demo咯。
    段(组)头:通过 `- (nullable UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section`获取
    段(组)尾巴:通过 `- (nullable UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section`获取
    Cell : 通过 `- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath` 获取
    这能明白吗???
  • 呃哈哈:如果我说百度云失效了,你信不信
    麻烦给我发一下好吗,谢谢了
    呃哈哈:@CoderMikeHe 试过了。三遍
    CoderMikeHe:@呃哈哈 去过github上去,那个是最新的
  • 953641bb06b7:大神哥哥,能把代码一写成能评论的样子吗
    953641bb06b7:@CoderMikeHe 今天上午我试过了,没成功~~可能我比较菜:sweat: ,还有评论后滑倒当前评论的位置,我想按照优酷视频那个写,但是看不明白。。:sob:
    CoderMikeHe:@开水上锅 评论无非是拼接数据罢了
    953641bb06b7:功能一
  • 953641bb06b7:CopyPNGFile /Users/lijie/Library/Developer/Xcode/DerivedData/MHDevelopExample-cgjniftsqgccnearzdpjeifgtvpi/Build/Products/Debug-iphonesimulator/MHDevelopExample.app/cmh_default_buy_goods@3x.png /Users/lijie/XNB/Resource/Architecture/Default/cmh_default_buy_goods@3x.png
    cd /Users/lijie/Desktop/下载在/MHDevelopExample_Objective_C/MHDevelopExample
    export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
    export PATH="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin:/Applications/Xcode.app/Contents/Developer/usr/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
    export SDKROOT=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator11.4.sdk
    export TOOLCHAINS=
    /Applications/Xcode.app/Contents/Developer/usr/bin/copypng -compress -strip-PNG-text /Users/lijie/XNB/Resource/Architecture/Default/cmh_default_buy_goods@3x.png /Users/lijie/Library/Developer/Xcode/DerivedData/MHDevelopExample-cgjniftsqgccnearzdpjeifgtvpi/Build/Products/Debug-iphonesimulator/MHDevelopExample.app/cmh_default_buy_goods@3x.png

    ERROR: Can't find /Users/lijie/XNB/Resource/Architecture/Default/cmh_default_buy_goods@3x.png
    Command /Applications/Xcode.app/Contents/Developer/usr/bin/copypng failed with exit code 1 下载后遇到这样的错误,两种方法都试过了
    CoderMikeHe:@开水上锅 好的,已经修复提交了。
    953641bb06b7:找到了删掉也没用
    953641bb06b7:而且这个cmh_default_buy_goods@3x.png这个图片找不到
  • 魏志军:大神如果评论那一条数据也没有,直接返回cell的高度为零可以吗,还是还有别的地方需要注意,望指教
    CoderMikeHe:@魏志军 一条数据都没有,怎么会去创建cell。
  • 魏志军:你是cell里面又嵌套一个tableView吗
    魏志军:@CoderMikeHe 大神如果评论那一条数据也没有,直接返回cell的高度为零可以吗,还是还有别的地方需要注意,望指教
    CoderMikeHe:@魏志军 https://www.jianshu.com/p/395bac3648a7 这个方案用的是 ` 组头 + Cell + 组尾`的方式做的,灰色部分每一条评论就是一个`Cell`。建议看完文章和看看Demo
  • 魏志军:如果整体部分是个cell的话,那为什么会是一行行的,这是怎么 做的,不理解
  • 魏志军:灰色部分整体是cell吗
  • 魏志军:评论哪如果整体是一个cell的话,那怎么一行行的啊
  • L05T:仔细研读了下,完美用在自己的项目中~
    CoderMikeHe:@L05T 其实并不难..其实很简单。:+1:
  • 899781bdee56:有一个问题,进入朋友圈以后,可以不可以吧评论和点点赞隐藏掉,用户想看朋友圈的评论的时候在显示出来,类似于微博。期待你的回复!!!!
    CoderMikeHe:@newdivide39 当然可以的呀,微博跟微信需求不一样吧。微博那种是通过数字的形式告诉用户,点赞数,评论数,转发数。如果是微博那种样式,直接采用Cell的方式即可,而微信这种采用 `组头 + Cell + 组尾`这种。当然微博实现方式,完全可以自行百度,一大堆。
  • 690a597c0ae8:后端数据库用的什么?
    690a597c0ae8:@CoderMikeHe 多谢回复,最近在把Firebase的project转移到国内的baas,有机会多交流iOS开发
    CoderMikeHe:@David_f31f 那得问后端了,前端只是拿数据来展示罢了。
  • EchooJ:pod install后报出已下错误
    [!] Error installing CHTCollectionViewWaterfallLayout
    [!] /usr/bin/git clone https://github.com/chiahsien/CHTCollectionViewWaterfallLayout.git /var/folders/wp/pfk_75q917dc0rjsrbbj7b4w0000gn/T/d20180403-1060-xcbw1 --template= --single-branch --depth 1 --branch 0.9.6

    Cloning into '/var/folders/wp/pfk_75q917dc0rjsrbbj7b4w0000gn/T/d20180403-1060-xcbw1'...
    error: RPC failed; curl 18 transfer closed with outstanding read data remaining
    fatal: The remote end hung up unexpectedly
    fatal: early EOF
    fatal: unpack-objects failed
    CoderMikeHe:@linlin泠迹 https://blog.csdn.net/drift_axe/article/details/54924359 你参照这个试试。
    EchooJ:@CoderMikeHe 不行啊,我试过了的,操作步骤就是按照你给的readme.md文件描述,到了pod install 后就出现该问题
    CoderMikeHe:@linlin泠迹 重新pod install
  • 82295265a0fd:楼主,这个我自己写了下,但是有个问题,就是段头下面的cell会有个默认的缩进动画。每个整体的section都有,很烦啊,楼主怎么解决的
    CoderMikeHe:@0号故事 哈哈,注意细节哈
    82295265a0fd:解决了,UITableViewStyleGrouped tableview类型。。我傻了
  • itonny:何时分享点 socket,以及长链接的文章啊
  • 大慧慧_2258:cd到项目根目录 执行pod install 还是不行额 请问怎么弄
    CoderMikeHe:@大慧慧_2258 https://pan.baidu.com/s/1skPKNhz 密码:6grn
    CoderMikeHe:@大慧慧_2258 具体是什么错误呢。
  • a9a307e7fb5d:这才是真正的自我完善的路,不只是会用,还能写出来,说明对知识点的梳理和运用已经很娴熟。demo和简述都很清楚,代码质量好高,大牛,膜拜膜拜。
    CoderMikeHe:@一声童谣 好的,必须的。
    a9a307e7fb5d:@CoderMikeHe 评论回复这块,先自己研究研究您的代码,如果有哪里不懂的,还望不惜赐教。 : )
    CoderMikeHe:@一声童谣 哈哈,谢谢,对你有帮助,才是文章意义所在哈。
  • Henrya:楼主也可以看看这个高仿微信朋友圈的demo,用的是SDAutolayout
    https://github.com/gsdios/GSD_WeiXin
    CoderMikeHe:@Henrya 那必须的。
    Henrya:@CoderMikeHe 言之有理,先研究下楼主的写法。开源精神值得称赞!
    CoderMikeHe:@Henrya 嗯嗯 ,已借鉴过,但是在朋友圈这块,其实DSD_WeiXin性能十分不友好,一旦评论数据过多,由于DSD_WeiXin的评论展示是一个简单的View,这样做不到复用,一旦你滚动的时候,这个View就会先删掉所有的子控件,在添加子控件,这是在程序开发要避免的,尽量一口气创建完,然后控制其隐藏显示。DSD_WeiXin主要是想体现SDAutolayout的实用性,突出的重点是自动布局。 所以,针对类似微信这种支持无限评论的话。还是建议使用我用的这个方案。还是根据各自场景,使用不同方案吧。
  • PGOne爱吃饺子:楼主的这个获取富文本是怎么搞的,思路是怎么样的,打印了一下富文本,好乱啊,能不能给个思路
    PGOne爱吃饺子:@CoderMikeHe 问一下,你这里面一个人回复一个人之后,下个回复好像有一个空格,请问空格也是在里面拼接的么
    PGOne爱吃饺子:@CoderMikeHe 好的 谢谢
    CoderMikeHe:@4140d18ee6fc 建议你先看看 YYText 的使用方法。 顺便看看 YYKit的Demo。思路无非就是拼接数据,以及处理富文本的点击事件即可。
  • 兰德耍:pod install

    好多库啊 0.0。已经迫不及待了
    最近也在做类似的项目。希望有帮助
    兰德耍:@CoderMikeHe
    CoderMikeHe:@兰德耍 嗯嗯,主要里面有好几个Demo,可能每个库服务不同的Demo
  • piaodang1234: 你好作者,你这修改了cell的frame,那么如果点击cell左侧的区域如何响应呢?
    CoderMikeHe:@piaodang1234 好的 ,最近较忙。有时间我验证验证哈 。
    piaodang1234:@CoderMikeHe hello 做法有两个:1.在cell中通过hittest来获取point的坐标的x为负值的话,则是cell外面,但是使用hitTest存在问题,当点击第一个section,hitTest执行了6次,往下滑动在点击的话hitTest执行了几十次,在stackoverflow上面没有查到解决方法,所以不推荐
    2.自定义UITableView,在这里面通过touchBegain来判断点击的view和point,当点击的view为HeaderfooterView则忽略,如果点击的View为当前自定义的UITableView,那么修改point的x值,使x位于cell的frame内,然后通过indexPathForRowAtPoint获取到点击的indexPath,通过协议返回到ViewController中
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    if ([touch.view isKindOfClass:[self class]]) {
    CGPoint originalLocation = [touch locationInView:self];
    originalLocation.x = CGRectGetWidth(self.frame) / 2.0;//此处需要根据实际情况调整,确保x的值在cell的frame内
    NSIndexPath *indexPath = [self indexPathForRowAtPoint:originalLocation];
    if (self.ksDelegate && [self.ksDelegate respondsToSelector:@selector(tableView:clickOutOfCellAtIndexPath:)]) {
    [self.ksDelegate tableView:self clickOutOfCellAtIndexPath:indexPath];
    }
    }
    [super touchesBegan:touches withEvent:event];
    }
    推荐使用第二种方法,感觉比较完美
    CoderMikeHe:@piaodang1234 嗯嗯,我很早发现了这个问题,例如优酷视频的评论点击cell左侧是可以响应的,个人觉得严禁的做法,是在cell左侧的区域,添加一个view,利用hitTest方法来处理。有时间会完善一下。
    但是,我们程序猿也得强硬一点,用户点击左侧没响应,会乖乖去点击cell。
  • 脚下的斑马线:作者你好,组头的高度是自己算的么?
    CoderMikeHe:@城北小客 对的,都是自己算,没有使用autoLayout。用代码换性能吧。
  • 没有名字就是我的名字:欢迎各路大神没事来这群里面吹吹技术的牛逼 聊聊技术的问题,超过100人改为付费群,且行且珍惜号:614194935
  • 嘿丶花姑娘:为什么回复列表不用YYText做呢,用\n换行 在设置一个行间距,和magin,一样可以实现这个效果,而且效果更好,滚动更流畅
    CoderMikeHe:@嘿花姑娘 如果用一个YYText代替整个回复列表 ,那是非常不妥,想想如果有100条回复数据,如果你一直去拼接数据,工程量太大;其次,事件处理将变得复查;
  • 7a45b5f6be54:代码写的太规范了,看的眼睛发亮,:sob:我都不想看自己写的代码了。
    CoderMikeHe:@相_c0f8 利人利己,何乐不为。
  • Aacmr:楼主加上评论折叠功能呀, 还有那个单行折叠。我已经做过一种,想看看你的比较好的实现方式。
    CoderMikeHe:展开评论这个功能,就类似于扣扣的分组功能,利用组头+cell非常容易实现,只要在MHTopic增加一个属性来判断是否展开评论数据,如果是隐藏评论数据,那门就在tableview的返回多少个cell的代理中,return 0即可反之如果显示评论数据,那门就正常返回即可。
    Aacmr:@CoderMikeHe 展开全文是一种,还有一种展开评论,不知道是获取行高合理,还是获取评论的个数合理。
    CoderMikeHe:@Aacmr 请问是类似微信的 展开全文 那种吗??
  • EdenChow:良心大牛。
    CoderMikeHe:@Eden_chow 没有,只是自己平常开发遇到的坑而已,希望对你有所帮助
  • 6b985f46497d:可以呀 小伙子
  • 酒红色T恤:良心好文,赞一个!
    CoderMikeHe:@低碳环保_好好学习 谢谢,互相学习。
  • 搜捕儿:博主优酷的demo用的是方法一还是方法二
    CoderMikeHe:@搜捕儿 用的是方法一。
  • 就是一个春天的花朵:良心:+1: Demo写的这么清晰
    就是一个春天的花朵:@CoderMikeHe 弱弱的问一句,这个是不是就是MVVM的用法了,用两层model
    就是一个春天的花朵:@CoderMikeHe 好的,我算是学艺不精了,之前一直只是把model简单的用来存储数据模型,没想到还能有这么好的用法.还得继续学习呀:smile:
    CoderMikeHe:@ozill 谢谢,我会继续努力的。喜欢的话请在 github 上star一下,有时间我会把我平常遇到的问题全部分享出来。一起学习,共同进步。
  • c2fffd2b0090:有demo吗?给个链接啊
    CoderMikeHe:@王丹阳1995 前提你得支持cococapods,在终端cd到项目的根目录,执行pod install即可,我github上 不是有说明的么?
    8fe8946fa366:请问怎么pod install@CoderMikeHe
    CoderMikeHe:@打了鸡血 我刚更新本文文章,文章末尾有链接地址,第一次使用Demo需要pod install。若文章对你有帮助,还请给我好评❤️。谢谢

本文标题:iOS 实现微信朋友圈评论回复功能(一)

本文链接:https://www.haomeiwen.com/subject/nwcwittx.html