iOS开发——UI_swift篇&TableView自定义聊天界面
TableView自定义聊天界面
- (1)消息可以是文本消息也可以是图片消息
- (2)消息背景为气泡状图片,同时消息气泡可根据内容自适应大小
- (3)每条消息旁边有头像,在左边表示发送方,在右边表示接收方
- (1)需要定义一个数据结构保存消息内容 MessageItem
- (2)继承UITableViewCell实现自定义单元格,这里面放入头像和消息体
- (3)继承UITableView实现自定义表格,通过读取数据源,进行页面的渲染
- (4)消息体根据内容类型不同,用不同的展示方法
- (5)每个单元格的高度需要根据内容计算出来
- (6)数据由ViewController来提供初始化数据


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(, ,
self.view.frame.size.width, self.view.frame.size.height - ))
//创建一个重用的单元格
self.tableView!.registerClass(TableViewCell.self, forCellReuseIdentifier: "MsgCell")
var me = "xiaoming.png"
var you = "xiaohua.png"
var first = MessageItem(body:"嘿,这张照片咋样,我周末拍的呢!", logo:me,
date:NSDate(timeIntervalSinceNow:-), mtype:ChatType.Mine)
var second = MessageItem(image:UIImage(named:"luguhu.jpeg")!,logo:me,
date:NSDate(timeIntervalSinceNow:-), mtype:ChatType.Mine)
var third = MessageItem(body:"太赞了,我也想去那看看呢!",logo:you,
date:NSDate(timeIntervalSinceNow:-), mtype:ChatType.Someone)
var fouth = MessageItem(body:"嗯,下次我们一起去吧!",logo:me,
date:NSDate(timeIntervalSinceNow:-), mtype:ChatType.Mine)
var fifth = MessageItem(body:"好的,一定!",logo:you,
date:NSDate(timeIntervalSinceNow:), 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
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
{
, left:, bottom:, right:)
}
//设置他人的文本消息边距
class func getTextInsetsSomeone() -> UIEdgeInsets
{
, left:, bottom:, right:)
}
//设置我的图片消息边距
class func getImageInsetsMine() -> UIEdgeInsets
{
, left:, bottom:, right:)
}
//设置他人的图片消息边距
class func getImageInsetsSomeone() -> UIEdgeInsets
{
, left:, bottom:, right:)
}
//构造文本消息体
convenience init(body:NSString, logo:String, date:NSDate, mtype:ChatType)
{
var font = UIFont.boldSystemFontOfSize()
var width = , 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(, , size.size.width, size.size.height))
label.numberOfLines =
label.lineBreakMode = NSLineBreakMode.ByWordWrapping
label.text = (body.length != ? 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
//等比缩放
)
{
size.height /= (size.width / );
size.width = ;
}
var imageView = UIImageView(frame:CGRectMake(, , 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
import Foundation
/*
数据提供协议
*/
protocol ChatDataSource
{
/*返回对话记录中的全部行数*/
func rowsForChatTable( tableView:TableView) -> Int
/*返回某一行的内容*/
func chatTableView(tableView:TableView, dataForRow:Int)-> MessageItem
}
(4)自定义表格 TableView.swift
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 =
if ((self.chatDataSource != nil))
{
count = self.chatDataSource.rowsForChatTable(self)
)
{
; i < count; i++)
{
var object = self.chatDataSource.chatTableView(self, dataForRow:i)
bubbleSection.append(object)
}
//按日期排序方法
bubbleSection.sort({$.date.timeIntervalSince1970 < $.date.timeIntervalSince1970})
}
}
super.reloadData()
}
//第一个方法返回分区数,在本例中,就是1
func numberOfSectionsInTableView(tableView:UITableView)->Int
{
}
//返回指定分区的行数
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
if (section >= self.bubbleSection.count)
{
}
}
//用于确定单元格的高度,如果此方法实现得不对,单元格与单元格之间会错位
func tableView(tableView:UITableView,heightForRowAtIndexPath indexPath:NSIndexPath) -> CGFloat
{
// Header
)
{
return 30.0
}
var data = self.bubbleSection[indexPath.row - ]
)
}
//返回自定义的 TableViewCell
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)
-> UITableViewCell
{
var cellId = "MsgCell"
)
{
var data = self.bubbleSection[indexPath.row-]
var cell = TableViewCell(data:data, reuseIdentifier:cellId)
return cell
}
else
{
return UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: cellId)
}
}
}
(5)自定义单元格 TableViewCell.swift
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) ? : self.frame.size.width - width -
self.msgItem.insets.left - self.msgItem.insets.right
var y:CGFloat =
//显示用户头像
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) ? : self.frame.size.width -
//头像居于消息底部
var avatarY = height
//set the frame correctly
self.avatarImage.frame = CGRectMake(avatarX, avatarY, , )
self.addSubview(self.avatarImage)
var delta = self.frame.size.height - (self.msgItem.insets.top + self.msgItem.insets.bottom
+ self.msgItem.view.frame.size.height)
)
{
y = delta
}
if (type == ChatType.Someone)
{
x +=
}
if (type == ChatType.Mine)
{
x -=
}
}
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:(,topCapHeight:)
}
else {
self.bubbleImage.image =
UIImage(named:, topCapHeight:)
}
self.bubbleImage.frame = CGRectMake(x, y, width + self.msgItem.insets.left
+ self.msgItem.insets.right, height + self.msgItem.insets.top + self.msgItem.insets.bottom)
}
}

iOS开发——UI_swift篇&TableView自定义聊天界面的更多相关文章
- iOS开发——UI_swift篇&TableView实现页眉和页脚
TableView实现页眉和页脚 在UItableView中header和footer是很常见的,而且他能让你实现很复杂的功能,我们见过最多的就是下拉刷新和上啦加载更多,当然你还可以在上面添加一个 ...
- iOS开发UI篇—Quartz2D(自定义UIImageView控件)
iOS开发UI篇—Quartz2D(自定义UIImageView控件) 一.实现思路 Quartz2D最大的用途在于自定义View(自定义UI控件),当系统的View不能满足我们使用需求的时候,自定义 ...
- iOS开发多线程篇 11 —自定义NSOperation
iOS开发多线程篇—自定义NSOperation 一.实现一个简单的tableView显示效果 实现效果展示: 代码示例(使用以前在主控制器中进行业务处理的方式) 1.新建一个项目,让控制器继承自UI ...
- IOS开发UI篇之──自定义UIActionSheet
转载自:http://www.cnblogs.com/pengyingh/articles/2343200.html UIActionSheet类系IOS开发中实现警告框的重要的类,而在好多应用中,都 ...
- iOS开发——UI_swift篇&UITableView实现索引功能
UITableView实现索引功能 关于UItableView的索引在平时项目中所见不多,最多的就是跟联系人有关的界面,虽然如此,但是作为一个swift开发的程序必须知道的一个技术点,所以今天 ...
- iOS开发——UI_swift篇&UITableView实现单元格展开与隐藏
UITableView实现单元格展开与隐藏 关于UITableView的展开的收缩在前面的文章我已经结束,就是使用代理,通知,block传值的时候实现的,当时是使用一个Bool值来实现,最后使用着三 ...
- iOS开发——UI_swift篇&UItableView实现移动单元格
UItableView实现移动单元格 1,下面的样例是给表格UITableView添加单元格移动功能: (1)给表格添加长按功能,长按后表格进入编辑状态 (2)在编辑状态下,可以看到单元格后面出现 ...
- iOS开发UI篇-tableView在编辑状态下的批量操作(多选)
先看下效果图 直接上代码 #import "MyController.h" @interface MyController () { UIButton *button; } @pr ...
- IOS开发UI篇之──自定义加载等待框(MBProgressHUD)
本文转载至 http://blog.csdn.net/xunyn/article/details/8064984 原文地址http://www.189works.com/article-89289 ...
随机推荐
- [Everyday Mathematics]20150106
(1). 设 $f\in C[0,T]$, $g$ 是 $T$-周期函数, 试证: $$\bex \vlm{n}\int_0^T f(x)g(nx)\rd x=\frac{1}{T}\int_0^T ...
- 利用原生JavaScript获取样式的方式小结
来源:http://www.ido321.com/930.html ps:是获取样式,不是设置样式.若没有给元素设置样式值,则返回浏览器给予的默认值.(论坛整理) 1.element.style:只能 ...
- 2016年VR&AR有市场吗?
新霸哥发现了近期虚拟现实(VR)和增强现实(AR)非常火,已经成为了科技产业中最具前景的技术之一.其实说起这两项技术的应用,人们最容易把它与电子游戏联系在一起,那么在2016年VR&AR有市场 ...
- matlab的&和&&操作
A&B(1)首先判断A的逻辑值,然后判断B的值,然后进行逻辑与的计算.(2)A和B可以为矩阵(e.g. A=[1 0],B=[0 0]).A&&B(1)首先判断A的逻辑值,如果 ...
- 【转】VC6.0附带小工具软件一览
)ActiveX Control Test Container称为"ActiveX 控件测试容器",顾名思义,此工具的主要功能就是测试ActiveX 控件,可以通过改变Active ...
- linux 命令 之chomd
chmod用于改变文件或目录的访问权限.用户用它控制文件或目录的访问权限.该命令有两种用法.一种是包含字母和操作符表达式的文字设定法:另一种是包含数字的数字设定法. 1. 文字设定法 语法:chmo ...
- 第二百八十五天 how can I 坚持
今天好平凡啊. 晚上给徐斌打电话说忘带钥匙了,一块吃了个饭. 回到家,什么都不想做,好消沉. 玩了几局象棋,很多东西只是玩玩,但还是会认真,认真就会输,好惨. 最近在关注万科幸福里,可是.首付付不起啊 ...
- homework-08
这次作业是考察关于C++的一些使用,由于我的C++只掌握了基本功,所以我只有霸王硬上弓,勉强写写自己的浅见. 1. 理解C++变量的作用域和生命周期 对一个C++变量来说,有两个属性非常重要:作用域和 ...
- c语言中register类型的变量
C语言中: 一.register变量 关键字regiter请求编译器尽可能的将变量存在CPU的寄存器中.有以下几点注意的地方. register变量必须是能被CPU寄存器所接受的类型,这通常意味着re ...
- 递归函数recursion
1(调用自身)递归函数是‘自己调用自己‘的函数,不管这样的调用是直接的还是间接的. 2(递归出口)因为函数不可以一直调用自己,无法停止工作,所以递归函数一定具备结束条件. http://www.cnb ...