下面讨论一下微信朋友圈的实现方式。先分析结构,和布局。

微信朋友圈,看起来很有秩序,而且滑动的时候也不卡,应用的非常好。对于微信朋友圈的样式,我们可以大致分成以下6种类型。

  • 纯文字类型
  • 单张图得显示
  • 多张图得显示(按照九宫格排练)
  • 链接类型
  • 视频类型
  • 广告类型

那么我们需要分析每种类型的布局有什么共同点,和不同点。

每种类型都是有一个头像和一个姓名,这个是必须的,我们可以封装到父类里。每种类型,都可以附带文字说明,也可以不带,我们也可以封装到父类里,但是这个不是必须要创建的时候,就生成的,而是根据当前有没有文字说明来生成的,所有说他应该是动态生成的,对于复用我们可以用隐藏。最好不要从父类移除。

还有就是评论,每种类型都可以评论。那么我们就要把评论封装到一起。也可以封装到父类。对于显示时间这个也是必须的我们也可以封装到父类里。

那么我们可以看到如下结构:

以一个多张图类型,我们分析一下,红框算一个cell,只有黑框位置的内容是不一样的,所以我们只要把黑框以外的分装好做成基类,其他的类型都继承基类,这样我们就能减少布局的变化,并且还能更多的复用。

那么我们用MVC的模式来分析:

  • 模型
class JHSMessageModel: NSObject {var name = "";var modelType: MessageModelType!var contentText: String!init(type: MessageModelType) {super.init();modelType = type;self.configData();}func configData() -> Void {}private var _contextSize: CGSize!var contextSize: CGSize {if contentText == nil {return CGSize.zero;}if _contextSize != nil {return _contextSize;}_contextSize = contentText.textSize(size: CGSize(width: PengConfigParamter.maxWidth, height: CGFloat.greatestFiniteMagnitude), font: PengConfigParamter.textFont);return _contextSize;}var nameSize: CGSize {let size = name.textSize(size: CGSize(width: PengConfigParamter.maxWidth, height: CGFloat.greatestFiniteMagnitude), font: PengConfigParamter.textFont);return size;}var topHeight: CGFloat {let ht = (contextSize.height + 8) + nameSize.height + 12;return ht;
//        let ht = contextSize.height + nameSize.height + 14;
//        return ht < 60 ? 60 : ht;}private var _cHeight: CGFloat = 0;var commentHeight: CGFloat {if comment == nil || comment.count == 0 {return 0;}if _cHeight != 0 {return _cHeight;}for (_,item) in comment.enumerated() {_cHeight += (item.size.height + 4)}_cHeight += 20;return _cHeight;}var rowHeight: CGFloat {return topHeight + commentHeight + 6;}var comment: [JHSCommentModel]!}

基类JHSMessageModel封装了共有的信息。姓名,类型,文字说明等属性,还有一些共有的方法。

  • 纯文字类型Model

只有文字类型的cell实际上和上边这个也是一样的,但是它是为了基类使用的,所有我们还需要定义它的子类。如下:

class JHSTextModel: JHSMessageModel {}
  • 单张图得显示Model
class JHSImageModel: JHSMessageModel {var urlString = "";var image: UIImage!override var topHeight: CGFloat {let ht = super.topHeight;return ht + 200;}var supHeight: CGFloat {return super.topHeight;}
}
  • 多张图得显示(按照九宫格排练)Model
class JHSMutableImageModel: JHSMessageModel {var images: [UIImage]!var count = 8 {didSet{count = count > 8 ? 8: count;images.removeAll();for idx in 0...count {images.append(UIImage(named: "\(idx).jpg")!);}}}override func configData() {images = [UIImage]();for idx in 0...count {images.append(UIImage(named: "\(idx).jpg")!);}}override var topHeight: CGFloat {if images == nil {return super.topHeight;}let perWidth = (PengConfigParamter.maxWidth - 8 - 40) / 3 + 4;let row = ceil(Double(images.count) / 3.0)return super.topHeight + perWidth * CGFloat(row);}var supTopHeight: CGFloat {return super.topHeight;}var cellImageHeight: CGFloat {return topHeight - super.topHeight;}
}
  • 链接类型Model
class JHSNewModel: JHSMessageModel {override var topHeight: CGFloat {return super.topHeight + 48;}var link = "链接地址";var linkTitle = "标题";var lineImage : UIImage!;}

对于model 基本的数据都已经有了,那么我们看看Model的view

先看基类的View:

class JHSGroupCell: UITableViewCell {var entity: JHSMessageModel!var leftImage: UIImageView!var nameLabel: UILabel!var contextLabel: UILabel!var tabBarView: JHSOperationView!var actionTarget: Any!var selector: Selector!fileprivate var commentView: JHSCommentItemView!var comments: [JHSCommentModel]! {didSet{configComment();}}var leftPointX: CGFloat {return leftImage.maxX + 10;}var topPointY: CGFloat {return nameLabel.maxY + 8;}var maxWidth: CGFloat {return PengConfigParamter.maxWidth}override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {super.init(style: style, reuseIdentifier: reuseIdentifier);backgroundColor = UIColor.white;selectionStyle = .none;leftImage = createImageView(rect: .init(x: 10, y: 10, width: 40, height: 40));leftImage.contentMode = .scaleAspectFill;leftImage.clipsToBounds = true;leftImage.layer.masksToBounds = true;leftImage.layer.cornerRadius = 4;leftImage.image = UIImage(named: "1.jpg");nameLabel = createLabel(rect: .init(x: leftPointX, y: 10, width: 20, height: 14), text: "姓名");nameLabel.font = PengConfigParamter.textFont;nameLabel.textColor = PengConfigParamter.textColor;tabBarView = JHSOperationView(frame: .init(x: leftPointX, y: topPointY, width: PengConfigParamter.maxWidth, height: 30));addSubview(tabBarView);configSubView();}func configSubView() -> Void {}private func configComment() {if comments != nil && commentView == nil {commentView = JHSCommentItemView(frame: .init(x: leftPointX, y: nameLabel.maxY, width: maxWidth, height: 40));addSubview(commentView);}commentView?.comments = comments;commentView?.isHidden = comments == nil;}private func configContent(context: String?) -> Void {if context == nil {contextLabel?.text = "";return;}if contextLabel == nil {contextLabel = createLabel(rect: .init(x: leftPointX, y: topPointY, width: maxWidth, height: 20), text: "");contextLabel.numberOfLines = 0;contextLabel.font = PengConfigParamter.textFont;contextLabel.textColor = PengConfigParamter.textColor;}contextLabel.text = context;}required init?(coder aDecoder: NSCoder) {fatalError("init(coder:) has not been implemented")}func configMessage(model: JHSMessageModel) -> Void {entity = model;nameLabel.text = model.name;configContent(context: model.contentText);comments = model.comment;}func addTarget(t: Any,sel: Selector) -> Void {self.actionTarget = t;selector = sel;}override func layoutSubviews() {super.layoutSubviews();if entity == nil {return;}var rect = nameLabel.frame;rect.size = entity.nameSize;nameLabel.frame = rect;if let label = contextLabel {rect = label.frame;rect.size = entity.contextSize;label.frame = rect;}if let cell = self as? JHSVideoCell {guard let imageModel = entity as? JHSVideoModel else{return;}rect = cell.backImage.frame;rect.origin.y = imageModel.supHeight;cell.backImage.frame = rect;rect = tabBarView.frame;rect.origin.y = cell.backImage.maxY;tabBarView.frame = rect;cell.backImage.image = UIImage(named: "1.jpg");}else if self is JHSTextCell {var rect = tabBarView.frame;rect.origin.y = entity.topHeight;tabBarView.frame = rect;}else if let cell = self as? JHSImageCell {if let imageModel = entity as? JHSImageModel {rect = cell.backImage.frame;rect.origin.y = imageModel.supHeight;cell.backImage.frame = rect;rect = tabBarView.frame;rect.origin.y = cell.backImage.maxY;tabBarView.frame = rect;}}else if let cell = self as? JHSMutableImageCell {guard let imgs = cell.mutableImages else {return;}let perWidth = (PengConfigParamter.maxWidth - 8 - 40) / 3;for item in imgs.enumerated() {let row = item.offset / 3;let column = item.offset % 3;let drawRect = CGRect(x: column.cgFloat * (perWidth + 4) + leftPointX, y: row.cgFloat * (perWidth + 4) + cell.topHeight, width: perWidth, height: perWidth);let img = cell.getImageBy(index: item.offset, rect: drawRect);img.image = item.element;img.isHidden = false;}if imgs.count < 9 {for idx in imgs.count...8 {let img = cell.getImageBy(index: idx, rect: CGRect.zero);img.isHidden = true;}}if let model = entity as? JHSMutableImageModel {var rect = tabBarView.frame;rect.origin.y = model.topHeight;tabBarView.frame = rect;}}else if let cell = self as? JHSNewCell {rect = cell.linkView.frame;rect.origin.y = entity.topHeight - 48;cell.linkView.frame = rect;rect = tabBarView.frame;rect.origin.y = entity.topHeight;tabBarView.frame = rect;}if let cView = commentView {rect = cView.frame;rect.origin.y = tabBarView.maxY;rect.size.height = entity.commentHeight;cView.frame = rect;}}
}
  • 纯文字类型View
class JHSTextCell: JHSGroupCell {}
  • 单张图得显示View
class JHSImageCell: JHSGroupCell {var backImage: UIImageView!override func configMessage(model: JHSMessageModel) {super.configMessage(model: model);if let cModel = model as? JHSImageModel {backImage.image = cModel.image;}}override func configSubView() {backImage = createImageView(rect: .init(x: leftPointX, y: topPointY, width: 160, height: 200));addSubview(backImage);backImage.contentMode = .scaleAspectFill;backImage.clipsToBounds = true;}
}
  • 多张图得显示(按照九宫格排练)View
class JHSMutableImageCell: JHSGroupCell {var mutableImages: [UIImage]! {didSet{setNeedsLayout();}}var topHeight: CGFloat {if let model = entity as? JHSMutableImageModel {return model.supTopHeight;}return 0;}private var imageTag = 12345;override func configSubView() {backgroundColor = UIColor.white;}override func configMessage(model: JHSMessageModel) {super.configMessage(model: model);if let imgsModel = model as? JHSMutableImageModel {mutableImages = imgsModel.images;}}func getImageBy(index: Int,rect: CGRect) -> UIImageView {var img = viewWithTag(index + imageTag) as? UIImageView;if img == nil {img = createImageView();img?.tag = index + imageTag;img?.contentMode = .scaleAspectFill;img?.clipsToBounds = true;}if !rect.isNull {img?.frame = rect;}return img!;}override func addTarget(t: Any, sel: Selector) {}override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {fetchImageIndex(touches, isEnd: false);}func fetchImageIndex(_ touches: Set<UITouch>,isEnd: Bool) -> Void {guard let point = touches.first?.location(in: self) else{return;}var index = -1;for idx in 0...8 {let rect = getImageBy(index: idx, rect: CGRect.null).frame;if !rect.isNull && rect.contains(point) {index = idx;break;}}if index != -1 ,let sel = selector , isEnd{let obs = actionTarget as? NSObject;obs?.perform(sel, with: [JHSCellKey.cell:self,JHSCellKey.imgIndex:index]);}}override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {fetchImageIndex(touches, isEnd: true);}override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {fetchImageIndex(touches, isEnd: false);}}
  • 链接类型View
class JHSNewCell: JHSGroupCell {var linkView: JHSLinkView!override func configSubView() {linkView = JHSLinkView(frame: .init(x: leftPointX, y: topPointY, width: PengConfigParamter.maxWidth, height: 48));addSubview(linkView);}override func configMessage(model: JHSMessageModel) {super.configMessage(model: model);if let lModel = model as? JHSNewModel {linkView.content = lModel.linkTitle;linkView.leftImg.image = lModel.lineImage;}}override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {guard let point = touches.first?.location(in: self) else {return;}if linkView.frame.contains(point),let sel = selector {let obj = actionTarget as? NSObject;obj?.perform(sel, with: [JHSCellKey.cell:self]);}}}

对于这样的设计我们就很好的运到实际工作共,那么我么也附上deom

demo地址链接。

iOS 仿微信朋友圈实现相关推荐

  1. IOS仿微信朋友圈的日期处理

    IOS仿微信朋友圈的日期处理 经常刷微信朋友圈的朋友,都能看到该条信息是什么发送的,有刚刚,有昨天,有xxxx年xx月xx日发送的,今天我们就探究微信内部是怎么样去做的. 对于传入的时间,一般是从服务 ...

  2. iOS - 仿微信朋友圈视频剪切功能

    分析需求 我们先看一看微信的界面 微信效果图 1.页面下部拖动左边和右边的白色竖条控制剪切视频的开始和结束时间,预览界面跟随拖动位置跳到视频相应帧画面,控制视频长度最长15秒,最短5秒 2.拖动下部图 ...

  3. iOS粒子特效、仿微信朋友圈、转场动画、抢红包动画等源码

    iOS精选源码 viewController 之间的转场动画 swift版 视频添加水印及粒子特效 小红点(消息推送提醒)完整解决方案 仿微信朋友圈–CircleOfFriendsDisplay 图片 ...

  4. Android 仿微信朋友圈添加图片

    github地址(欢迎下载Demo) https://github.com/zhouxu88/WXCircleAddPic 老习惯,先上图,着急用的朋友,直接带走Demo,先拿来用吧,毕竟老板催的紧, ...

  5. android 仿微信朋友圈 评论,2020年android 仿微信朋友圈 评论

    2020年android 仿微信朋友圈 评论 1.如果有人问我:那些艰难的岁月你是怎么熬过来的?我想我只有一句话回答:我有一种强大的精神力量支撑着我,这种力量名字叫"想死又不敢" ...

  6. php仿微信朋友圈网站源码,Smobiler仿微信朋友圈的消息代码实例

    这篇文章主要介绍了.Net语言Smobiler开发平台如何仿微信朋友圈的消息样式?本文为大家揭晓答案 最前面的话:Smobiler是一个在VS环境中使用.Net语言来开发APP的开发平台,也许比Xam ...

  7. Android仿微信朋友圈7实现点赞功能

    前言: 之前一直有朋友问我点赞怎么实现?今天趁着休息时间整理出来,其实点赞的功能和用户评论差不多,都是显示一个用户列表,只不过评论有评论内容和回复评论功能.实现点赞的思路如下: 1.当用户点击点赞按钮 ...

  8. Android自定义弹窗模仿微信,Android 仿微信朋友圈点赞和评论弹出框功能

    本文简单模仿微信朋友圈的点赞和评论弹出框,布局等细节请忽略,着重实现弹出框.发评论,及弹出位置的控制. 1. 微信弹出框 微信朋友圈的点赞和评论功能,有2个组成部分: 点击左下角的"更多&q ...

  9. Android仿微信朋友圈4实现评论动态时输入框和软键盘自动定位到内容下面

    最近做完朋友圈功能后,测试提出一个功能优化,在某些发布的动态下评论时软键盘和输入框遮当内容了,这个用户体验感觉不是很好,于是根据今日头条和其他热门的App评论时软键盘和输入框都是在内容下面.Scrol ...

  10. 仿微信朋友圈【九宫格的实现】

    仿微信朋友圈[九宫格的实现] 标签: 九宫格自定义viewgroup 2017-04-18 18:39  561人阅读  评论(0)  收藏  举报   分类: Android(25)  版权声明:本 ...

最新文章

  1. 大竹中学2021高考成绩查询,2021年大竹中学升学率高不高?
  2. pythonurllib模块-python模块之urllib
  3. 【译】Consortium Chain Development
  4. the code place where the binding is converted to final value displayed in u
  5. 阿里云存储OSS中设置上传文件content type
  6. python json是什么_python json详解
  7. Java文本预处理 去除非法字符
  8. 更高效地刷OJ——Java中常用的排序方法,Array.sort(),Arrays.parallelSort(), Collections.sort()
  9. MySQL存储过程 游标
  10. Python_base_正则表达式
  11. PHPStorm Mac如何利用MAMP配置php?
  12. Ubuntu14.04 64位安装iNode客户端
  13. 实用的截屏、录屏、图片识字工具推荐
  14. diskgenius扩容c盘重启电脑卡住_DiskGenius怎么给C盘扩容?DiskGenius无损调整C盘容量方法 (全文)...
  15. 李商隐和杜牧并称“小李杜”,他俩到底谁的成就高?
  16. 是如何通过阿里面试的?
  17. NR-PRACH:prach格式以及时频域情况
  18. 西门子1200plc两部六层电梯程序
  19. Neo4j 简单入门
  20. MOOC《基础和声》笔记

热门文章

  1. CI框架email类发送邮件失败无报错,开启debug模式的方法
  2. linux装完系统需要输入密码,在安装Linux系统的过程中,一定要设置root用户的密码 (5.0分)...
  3. 如何拼局域网所有ip_查看局域网内所有ip
  4. shiny app制作基本思路
  5. GEE开发之Landsat8_NDVI的数据分析
  6. 华为HG8347R光猫 4台设备连接限制破解全过程
  7. 公众号运营实用小工具推荐
  8. 《C专家编程》笔记——第一章
  9. android 官方增量更新,Android 如何实现增量更新
  10. OpenWrt 路由器过滤广告的N种方法