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 UIKit
class 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 UIKit
class 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 UIKit
class 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 - 自定义单元格实现微信聊天界面相关推荐
- 企业微信每日给女友推送早安,5分钟快速部署,腾讯云部署版本,每日定时发送,天气,鸡汤,纪念日等信息,可自定义通知提醒名称,聊天界面可置顶,内容可查图片。
企业微信每日给女朋友推送早安,5分钟快速部署,每日定时发送,天气,鸡汤,纪念日等信息,可自定义通知提醒名称,聊天界面可置顶,内容可查图片. 先看效果 直接开搞 准备工作 1.企业id 2.企业应用se ...
- 【UIKit】表格自定义单元格(UITableViewCll)
自定义表格单元格(Cell)操作 使用NIb文件自定义单元格(Cell) 1. 创建UITableViewCell的子类,创建的同时记得选择生成xib文件(当然你也可以将控件通过代码 ...
- qtableview设置单元格颜色_一键解锁Excel自定义单元格格式!
实际工作中,常需要我们对单元格格式进行自定义设置,来突出显示我们需要看到的数据. 在自定义单元格格式时,我们常用如下方式先打开[设置单元格格式]对话框,再点击数字分类下的自定义: [开始]选项卡下的[ ...
- android 仿微信聊天界面 以及语音录制功能,Android仿微信录制语音功能
本文实例为大家分享了Android仿微信录制语音的具体代码,供大家参考,具体内容如下 前言 我把录音分成了两部分 1.UI界面,弹窗读秒 2.一个类(包含开始.停止.创建文件名功能) 第一部分 由于6 ...
- android模拟微信聊天功能,android仿微信聊天界面 语音录制功能
本例为模仿微信聊天界面UI设计,文字发送以及语言录制UI. 1先看效果图: 第一:chat.xml设计 android:layout_width="fill_parent" and ...
- excel格式设置:自定义单元格让数据大变身
"自定义单元格格式"允许用户创建一些特殊规则的格式,用于强调显示某些重要数据或信息.设置显示条件等.我相信大多数人都用过单元格格式设置,按快捷键ctrl+1就可以调出如下所示对话框 ...
- Excel 的自定义单元格格式
Excel中可设置每个单元格显示数字和文本的格式: Excel设置单元格数字格式的界面 用来自定义单元格格式的字符串的完整格式为: [条件1][颜色1]数字格式1;[条件2][颜色2]数字格式2;[颜 ...
- php写的微信聊天界面,浅谈 聊天界面 核心架构设计
本文以一个小例子简单的演示在微信小程序中使用环信SDK收发消息.官网demo 下载后把整个utils目录下的文件复制到咱自己工程的目录下.在WebIMConfig.js中将AppKey替换成自己应用的 ...
- iOS开发那些事--自定义单元格实现
自定义单元格 当苹果公司提供给的单元格样式不能我们的业务需求的时候,我们需要自定义单元格.在iOS 5之前,自定义单元格可以有两种实现方式:代码实现和用xib技术实现.用xib技术实现相对比较简单,创 ...
最新文章
- 《学习opencv》笔记——矩阵和图像处理——cvMinManLoc,cvMul,cvNot,cvNorm and cvNormalize...
- 最新 MSDN Library for Visual Studio 2008 SP1
- 快速使用Tensorflow读取7万数据集!
- Google Analytics使用说明
- python获取页面隐藏元素_selenium操作隐藏的元素(python+Java)
- URI 和 URL 的区别
- amap vueamap 与_vue 使用高德地图vue-amap组件过程解析
- 数据挖掘与数据化运营实战. 3.2 目标客户的预测(响应、分类)模型
- python3入门代码-Python3 教程 | 菜鸟教程
- mysql 窗口函数_7、MySQL高级功能(窗口函数)
- vs配置opencv
- 最新Jrebel激活码,Jrebel激活激活服务,Jrebel激活码,Jrebel破解
- linux测试硬盘速度命令,如何测试Linux磁盘的读写速度
- c语言字体取模软件下载,非常好用的lcd汉字取模软件
- 计算机考研复试_数据库
- pdf转word ocr_最强PDF转WORD软件:ABBYY FineReader
- Linux 简介 ------ 带你简单了解Linux
- Google搜索又变聪明了 Baidu你还能HOLD住吗
- Docker Jar项目启动慢
- 中国没有真正意义上的海滩比基尼(图)
热门文章
- Java多线程系列——深入重入锁ReentrantLock
- 详细讲解Android的网络通信(HttpUrlConnection和HttpClient)
- 「OC」类的深入研究、description方法和sel
- ubuntu12.04安装教程
- VMware workstation 8.0上安装VMware ESXI5.0
- 【短语学习】盈余量分析(earned value analysis)
- 网站前端设计,从960框架开始
- Linux环境变量PSI指什么,PSI 文件扩展名: 它是什么以及如何打开它?
- 下滑加载更多js_专治:卫生间免砸砖,房顶漏水,JS堵漏王水不漏,厂家三包产品,免费成熟配方(点开看更多)...
- 五大板块(1)—— 数组的定义,赋值与应用