Swift - 自定义单元格实现微信聊天界面
1,下面是一个放微信聊天界面的消息展示列表,实现的功能有:

|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
import UIKitclass ViewController: UIViewController, ChatDataSource { var Chats:Array<MessageItem>! var tableView:TableView! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. setupChatTable() } /*创建表格及数据*/ func setupChatTable() { self.tableView = TableView(frame:CGRectMake(0, 20, self.view.frame.size.width, self.view.frame.size.height - 20)) //创建一个重用的单元格 self.tableView!.registerClass(TableViewCell.self, forCellReuseIdentifier: "MsgCell") var me = "xiaoming.png" var you = "xiaohua.png" var first = MessageItem(body:"嘿,这张照片咋样,我周末拍的呢!", logo:me, date:NSDate(timeIntervalSinceNow:-600), mtype:ChatType.Mine) var second = MessageItem(image:UIImage(named:"luguhu.jpeg")!,logo:me, date:NSDate(timeIntervalSinceNow:-290), mtype:ChatType.Mine) var third = MessageItem(body:"太赞了,我也想去那看看呢!",logo:you, date:NSDate(timeIntervalSinceNow:-60), mtype:ChatType.Someone) var fouth = MessageItem(body:"嗯,下次我们一起去吧!",logo:me, date:NSDate(timeIntervalSinceNow:-20), mtype:ChatType.Mine) var fifth = MessageItem(body:"好的,一定!",logo:you, date:NSDate(timeIntervalSinceNow:0), mtype:ChatType.Someone) Chats = [first,second, third, fouth, fifth] self.tableView.chatDataSource = self self.tableView.reloadData() self.view.addSubview(self.tableView) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } /*返回对话记录中的全部行数*/ func rowsForChatTable(tableView:TableView) -> Int { return self.Chats.count } /*返回某一行的内容*/ func chatTableView(tableView:TableView, dataForRow row:Int) -> MessageItem { return Chats[row] }} |
(2)消息体数据结构 MessageItem.swift
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
import UIKit//消息类型,我的还是别人的enum ChatType{ case Mine case Someone}class MessageItem{ //头像 var logo:String //消息时间 var date:NSDate //消息类型 var mtype:ChatType //内容视图,标签或者图片 var view:UIView //边距 var insets:UIEdgeInsets //设置我的文本消息边距 class func getTextInsetsMine() -> UIEdgeInsets { return UIEdgeInsets(top:5, left:10, bottom:11, right:17) } //设置他人的文本消息边距 class func getTextInsetsSomeone() -> UIEdgeInsets { return UIEdgeInsets(top:5, left:15, bottom:11, right:10) } //设置我的图片消息边距 class func getImageInsetsMine() -> UIEdgeInsets { return UIEdgeInsets(top:11, left:13, bottom:16, right:22) } //设置他人的图片消息边距 class func getImageInsetsSomeone() -> UIEdgeInsets { return UIEdgeInsets(top:11, left:13, bottom:16, right:22) } //构造文本消息体 convenience init(body:NSString, logo:String, date:NSDate, mtype:ChatType) { var font = UIFont.boldSystemFontOfSize(12) var width = 225, height = 10000.0 var atts = NSMutableDictionary() atts.setObject(font,forKey:NSFontAttributeName) var size = body.boundingRectWithSize(CGSizeMake(CGFloat(width), CGFloat(height)), options:NSStringDrawingOptions.UsesLineFragmentOrigin, attributes:atts, context:nil) var label = UILabel(frame:CGRectMake(0, 0, size.size.width, size.size.height)) label.numberOfLines = 0 label.lineBreakMode = NSLineBreakMode.ByWordWrapping label.text = (body.length != 0 ? body : "") label.font = font label.backgroundColor = UIColor.clearColor() var insets:UIEdgeInsets = (mtype == ChatType.Mine ? MessageItem.getTextInsetsMine() : MessageItem.getTextInsetsSomeone()) self.init(logo:logo, date:date, mtype:mtype, view:label, insets:insets) } //可以传入更多的自定义视图 init(logo:String, date:NSDate, mtype:ChatType, view:UIView, insets:UIEdgeInsets) { self.view = view self.logo = logo self.date = date self.mtype = mtype self.insets = insets } //构造图片消息体 convenience init(image:UIImage, logo:String, date:NSDate, mtype:ChatType) { var size = image.size //等比缩放 if (size.width > 220) { size.height /= (size.width / 220); size.width = 220; } var imageView = UIImageView(frame:CGRectMake(0, 0, size.width, size.height)) imageView.image = image imageView.layer.cornerRadius = 5.0 imageView.layer.masksToBounds = true var insets:UIEdgeInsets = (mtype == ChatType.Mine ? MessageItem.getImageInsetsMine() : MessageItem.getImageInsetsSomeone()) self.init(logo:logo, date:date, mtype:mtype, view:imageView, insets:insets) } } |
(3)表格数据协议 ChatDataSource.swift
|
1
2
3
4
5
6
7
8
9
10
11
12
|
import Foundation/* 数据提供协议*/protocol ChatDataSource{ /*返回对话记录中的全部行数*/ func rowsForChatTable( tableView:TableView) -> Int /*返回某一行的内容*/ func chatTableView(tableView:TableView, dataForRow:Int)-> MessageItem} |
(4)自定义表格 TableView.swift
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
import UIKitclass TableView:UITableView,UITableViewDelegate, UITableViewDataSource{ //用于保存所有消息 var bubbleSection:Array<MessageItem>! //数据源,用于与 ViewController 交换数据 var chatDataSource:ChatDataSource! required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } override init(frame:CGRect) { self.bubbleSection = Array<MessageItem>() super.init(frame:frame, style:UITableViewStyle.Grouped) self.backgroundColor = UIColor.clearColor() self.separatorStyle = UITableViewCellSeparatorStyle.None self.delegate = self self.dataSource = self } override func reloadData() { self.showsVerticalScrollIndicator = false self.showsHorizontalScrollIndicator = false var count = 0 if ((self.chatDataSource != nil)) { count = self.chatDataSource.rowsForChatTable(self) if(count > 0) { for (var i = 0; i < count; i++) { var object = self.chatDataSource.chatTableView(self, dataForRow:i) bubbleSection.append(object) } //按日期排序方法 bubbleSection.sort({$0.date.timeIntervalSince1970 < $1.date.timeIntervalSince1970}) } } super.reloadData() } //第一个方法返回分区数,在本例中,就是1 func numberOfSectionsInTableView(tableView:UITableView)->Int { return 1 } //返回指定分区的行数 func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if (section >= self.bubbleSection.count) { return 1 } return self.bubbleSection.count+1 } //用于确定单元格的高度,如果此方法实现得不对,单元格与单元格之间会错位 func tableView(tableView:UITableView,heightForRowAtIndexPath indexPath:NSIndexPath) -> CGFloat { // Header if (indexPath.row == 0) { return 30.0 } var data = self.bubbleSection[indexPath.row - 1] return max(data.insets.top + data.view.frame.size.height + data.insets.bottom, 52) } //返回自定义的 TableViewCell func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { var cellId = "MsgCell" if(indexPath.row > 0) { var data = self.bubbleSection[indexPath.row-1] var cell = TableViewCell(data:data, reuseIdentifier:cellId) return cell } else { return UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: cellId) } }} |
(5)自定义单元格 TableViewCell.swift
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
import UIKitclass TableViewCell:UITableViewCell{ //消息内容视图 var customView:UIView! //消息背景 var bubbleImage:UIImageView! //头像 var avatarImage:UIImageView! //消息数据结构 var msgItem:MessageItem! required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } //- (void) setupInternalData init(data:MessageItem, reuseIdentifier cellId:String) { self.msgItem = data super.init(style: UITableViewCellStyle.Default, reuseIdentifier:cellId) rebuildUserInterface() } func rebuildUserInterface() { self.selectionStyle = UITableViewCellSelectionStyle.None if (self.bubbleImage == nil) { self.bubbleImage = UIImageView() self.addSubview(self.bubbleImage) } var type = self.msgItem.mtype var width = self.msgItem.view.frame.size.width var height = self.msgItem.view.frame.size.height var x = (type == ChatType.Someone) ? 0 : self.frame.size.width - width - self.msgItem.insets.left - self.msgItem.insets.right var y:CGFloat = 0 //显示用户头像 if (self.msgItem.logo != "") { var logo = self.msgItem.logo self.avatarImage = UIImageView(image:UIImage(named:(logo != "" ? logo : "noAvatar.png"))) self.avatarImage.layer.cornerRadius = 9.0 self.avatarImage.layer.masksToBounds = true self.avatarImage.layer.borderColor = UIColor(white:0.0 ,alpha:0.2).CGColor self.avatarImage.layer.borderWidth = 1.0 //别人头像,在左边,我的头像在右边 var avatarX = (type == ChatType.Someone) ? 2 : self.frame.size.width - 52 //头像居于消息底部 var avatarY = height //set the frame correctly self.avatarImage.frame = CGRectMake(avatarX, avatarY, 50, 50) self.addSubview(self.avatarImage) var delta = self.frame.size.height - (self.msgItem.insets.top + self.msgItem.insets.bottom + self.msgItem.view.frame.size.height) if (delta > 0) { y = delta } if (type == ChatType.Someone) { x += 54 } if (type == ChatType.Mine) { x -= 54 } } self.customView = self.msgItem.view self.customView.frame = CGRectMake(x + self.msgItem.insets.left, y + self.msgItem.insets.top, width, height) self.addSubview(self.customView) //如果是别人的消息,在左边,如果是我输入的消息,在右边 if (type == ChatType.Someone) { self.bubbleImage.image = UIImage(named:("yoububble.png"))!.stretchableImageWithLeftCapWidth(21,topCapHeight:14) } else { self.bubbleImage.image = UIImage(named:"mebubble.png")!.stretchableImageWithLeftCapWidth(15, topCapHeight:14) } self.bubbleImage.frame = CGRectMake(x, y, width + self.msgItem.insets.left + self.msgItem.insets.right, height + self.msgItem.insets.top + self.msgItem.insets.bottom) }} |
6,源码下载:
WeiXinChart.zip

Swift - 自定义单元格实现微信聊天界面的更多相关文章
- 浅谈DevExpress<五>:TreeList简单的美化——自定义单元格,加注释以及行序号
今天就以昨天的列表为例,实现以下效果:预算大于110万的单元格突出显示,加上行序号以及注释,如下图:
- android 仿微信聊天界面,以及语音录制功能
extends:http://104zz.iteye.com/blog/1709840 本例为模仿微信聊天界面UI设计,文字发送以及语言录制UI. 1先看效果图: 第一:chat.xml设计 ...
- HTML5仿手机微信聊天界面
HTML5仿手机微信聊天界面 这篇文章主要为大家详细介绍了HTML5仿手机微信聊天界面的关键代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 给大家带来的是HTML5仿手机微信聊天界面, ...
- jQuery MiniUI自定义单元格
监听处理"drawcell"事件 使用"drawcell"事件,可以自定义单元格内容.样式.行样式等. grid.on("drawcell" ...
- Android:日常学习笔记(8)———开发微信聊天界面
Android:日常学习笔记(8)———开发微信聊天界面 只做Nine-Patch图片 Nine-Patch是一种被特殊处理过的PNG图片,能够指定哪些区域可以被拉升,哪些区域不可以.
- 使用VUE组件创建SpreadJS自定义单元格(一)
作为近五年都冲在热门框架排行榜首的Vue,大家一定会学到的一部分就是组件的使用.前端开发的模块化,可以让代码逻辑更加简单清晰,项目的扩展性大大加强.对于Vue而言,模块化的体现集中在组件之上,以组件为 ...
- 使用VUE组件创建SpreadJS自定义单元格(二)
在上篇中,我们介绍了如何通过设置runtimeCompiler为true,在Vue中实现了动态创建电子表格组件.想了解具体内容可看点击查看使用VUE组件创建SpreadJS自定义单元格(一). 但是在 ...
- 剖析:如何用 SwitchUI 5天写一个微信 —— 聊天界面篇
前置资源 GitHub: SwiftUI-WeChatDemo 第零章:用 SwiftUI 五天组装一个微信 - wavky - 博客园 整体结构 UI 部分代码分布如上图所示,App 的主入口类为 ...
- NPOI 自定义单元格背景颜色-Excel
NPOI针对office2003使用HSSFWorkbook,对于offce2007及以上使用XSSFWorkbook:今天我以HSSFWorkbook自定义颜色为例说明,Office2007的未研究 ...
随机推荐
- android的事件分发机制理解
android的事件分发机制理解 1.事件触发主要涉及到哪些层面的哪些函数(个人理解的顺序,可能在某一层会一次回调其它函数) activity中的dispatchTouchEvent .layout中 ...
- sql2008R2sp1局域网镜像环境实操(无见证服务器)
环境介绍: 我的电脑:sql2008r2sp1_32 129.186.110.37 OS win2003 SP2 Enterprise 做主体服务器, 暂叫ServerA 服务器: sq ...
- Qt 释放新建窗口资源
当Widget *w = new Widget(); 不方便调用 delete w;时 Widget *w = new Widget(); w->setAttribute(Qt::WA_Dele ...
- 通过xml生成word文档
Xml生成word总结 使用xml生成word的基本步骤在<使用xslt转化xml数据形成word文档导出.doc>中说明比较清楚了.但是其中的细节并未说到,因此自己折腾了两天总算成功了. ...
- Ext的异步请求(二级级联动态加载下拉列表)
页面: <tr> <td class="label" width="300" >作业计划项模板</td> <td> ...
- 主题:Java WebService 简单实例
链接地址:主题:Java WebService 简单实例 http://www.iteye.com/topic/1135747 前言:朋友们开始以下教程前,请先看第五大点的注意事项,以避免不必要 ...
- 稳定婚姻问题和Gale-Shapley算法(转)
什么是算法?每当有人问作者这样的问题时,他总会引用这个例子:假如你是一个媒人,有若干个单身男子登门求助,还有同样多的单身女子也前来征婚.如果你已经知道这些女孩儿在每个男孩儿心目中的排名,以及男孩儿们在 ...
- Jetty总览
Jetty入门 基本功能介绍 配置概览-怎么配置Jetty 配置概览-须要配置什么 Jetty配置 部署到Jetty 配置上下文 配置连接器 配置安全 配置JSP支持 Jetty管理指导 启动Jett ...
- C语言中的enum(枚举)使用方法
近期在写数据结构的广义表时候用到了这个概念,在学习C语言的时候没有太注意们这里学一下. 我在网上结合了非常多资料,这里自己总结一下. 首先说.JAVA和C++中都有枚举类型. 假设一个变量你须要几种可 ...
- EasyUI - Menu 菜单
效果: html代码: <div id="mm" class="easyui-menu"> <div id =">New< ...