屏幕快照 2017-03-07 下午2.24.10.png
ViewController
import UIKit
class ViewController: UIViewController,chatDataSourch {
var tableView :TableView!
var messageArr :Array<messageModel>!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
buildTable()
}
func buildTable()
{
self.tableView = TableView(frame: CGRect(x: 0, y: 20, width: self.view.frame.size.width, height: self.view.frame.height-20), style: .plain)
self.tableView.register(tableViewCell.self, forCellReuseIdentifier: "GPLcell")
let me = "xiaoming.png"
let you = "xiaohua.png"
let first = messageModel(body:"嘿,这张照片咋样,我周末拍的呢!", logo:me,
date:NSDate(timeIntervalSinceNow:-600), mtype:chatType.Mine)
let second = messageModel(img: UIImage(named:"luguhu.jpeg")!, logo: me, date: NSDate(timeIntervalSinceNow:-290), mtype: chatType.Mine)
let third = messageModel(body:"太赞了,我也想去那看看呢!",logo:you,
date:NSDate(timeIntervalSinceNow:-60), mtype:chatType.Other)
let fouth = messageModel(body:"嗯,下次我们一起去吧!",logo:me,
date:NSDate(timeIntervalSinceNow:-20), mtype:chatType.Mine)
let fifth = messageModel(body:"好的,一定!",logo:you,
date:NSDate(timeIntervalSinceNow:0), mtype:chatType.Other)
self.messageArr = [first,second,third,fouth,fifth]
//数据协议
//代理方法
self.tableView.chatDataSource = self
self.tableView.reloadData()
self.view.addSubview(self.tableView)
}
//实现chatDataSourch代理方法
func rowsForChatTable(tableView: TableView) -> Int {
return self.messageArr.count
}
func chatTableView(tableView: TableView, dataForRow: Int) -> messageModel {
return self.messageArr[dataForRow]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
messageModel
import Foundation
import UIKit
//枚举,判断当前消息用户
enum chatType
{
case Mine
case Other
}
class messageModel {
//头像
var logo:String
//日期
var date:NSDate
//消息类型
var mytype :chatType
//内容视图
var view :UIView
//边距
var insets:UIEdgeInsets
/*
class func 类方法
*/
//设置我的文本消息边距
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)
}
init(logo:String, date:NSDate, mytype:chatType, view:UIView, insets:UIEdgeInsets) {
self.view = view
self.logo = logo
self.date = date
self.mytype = mytype
self.insets = insets
}
/*
convenience 优先级比较低
所有的 convenience 初始化方法都必须调用同一个类中的 designated 初始化完成设置
*/
//文字消息
convenience init(body:NSString, logo:String, date:NSDate, mtype:chatType)
{
let font = UIFont.boldSystemFont(ofSize: 12)
let width = 225.0, height = 10000.0
let atts = [NSFontAttributeName: font]
//计算字符串的高度
let size = body.boundingRect(with:CGSize(width: width, height: height), options: .usesLineFragmentOrigin, attributes: atts, context: nil)
let label = UILabel(frame: CGRect(x: 0, y: 0, width: size.size.width, height: size.size.height))
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping
label.text = (body.length != 0 ? body as String : "")
label.font = font
label.backgroundColor = UIColor.clear
let insets1:UIEdgeInsets = (mtype == chatType.Mine ?
messageModel.getTextInsetsMine() : messageModel.getTextInsetsSomeone())
self.init(logo:logo,date:date,mytype:mtype,view:label,insets:insets1)
}
//图片消息
convenience init(img:UIImage, logo:String, date:NSDate, mtype:chatType)
{
var size = img.size
//等比缩放
if size.width>220 {
size.height = (size.height)/(size.width / 220)
size.width=220
}
let imageView = UIImageView(frame:CGRect(x: 0, y: 0, width: size.width, height: size.height))
imageView.image = img
imageView.layer.cornerRadius = 5.0
imageView.layer.masksToBounds = true
let insets:UIEdgeInsets = (mtype == chatType.Mine ?
messageModel.getImageInsetsMine() : messageModel.getImageInsetsSomeone())
self.init(logo:logo,date:date,mytype:mtype,view:imageView,insets:insets)
}
}
chatDataSourch
import Foundation
import UIKit
//数据协议
protocol chatDataSourch
{
/*返回对话记录中的全部行数*/
func rowsForChatTable( tableView:TableView) -> Int
/*返回某一行的内容*/
func chatTableView(tableView:TableView, dataForRow:Int)-> messageModel
}
/*
protocol Student {
//类方法
static func study()
//实例方法
func changeName()
}
struct CollageStudent: Student {
//类方法实现
static func study() {
}
//实例方法实现
func changeName() {
}
}
//方法的调用
CollageStudent.study()
var c1 = CollageSt
*/
tableViewCell
import Foundation
import UIKit
class tableViewCell: UITableViewCell {
//消息内容视图
var customView:UIView!
//消息背景
var bubbleImage:UIImageView!
//头像
var avatarImage:UIImageView!
//消息数据结构
var msgModel:messageModel!
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
init(data:messageModel,reuseIdentifier cellId:String) {
self.msgModel = data
super.init(style: .default, reuseIdentifier: cellId)
rebuildUserInterface()
}
func rebuildUserInterface()
{
self.selectionStyle = UITableViewCellSelectionStyle.none
if (self.bubbleImage == nil)
{
self.bubbleImage = UIImageView()
self.addSubview(self.bubbleImage)
}
let type = self.msgModel.mytype
let width = self.msgModel.view.frame.size.width
let height = self.msgModel.view.frame.size.height
var x = (type == chatType.Other) ? 0 : self.frame.size.width - width -
self.msgModel.insets.left - self.msgModel.insets.right
var y:CGFloat = 0
if self.msgModel.logo != ""
{
let logo = self.msgModel.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
//别人头像,在左边,我的头像在右边
let avatarX = (type == chatType.Other) ? 2 : self.frame.size.width - 52
//头像居于消息底部
let avatarY = height
//set the frame correctly
self.avatarImage.frame = CGRect(x: avatarX, y: avatarY, width: 50, height: 50)
self.addSubview(self.avatarImage)
let delta = self.frame.size.height - (self.msgModel.insets.top
+ self.msgModel.insets.bottom + self.msgModel.view.frame.size.height)
if (delta > 0) {
y = delta
}
if (type == chatType.Other) {
x += 54
}
if (type == chatType.Mine) {
x -= 54
}
}
self.customView = self.msgModel.view
self.customView.frame = CGRect(x: (x + self.msgModel.insets.left), y: (y + self.msgModel.insets.top), width: width, height: height)
self.addSubview(self.customView)
//如果是别人的消息,在左边,如果是我输入的消息,在右边
if (type == chatType.Other)
{
//拉伸图片
self.bubbleImage.image = UIImage(named:("yoububble.png"))!
.stretchableImage(withLeftCapWidth: 21,topCapHeight:14)
}
else {
self.bubbleImage.image = UIImage(named:"mebubble.png")!
.stretchableImage(withLeftCapWidth: 15, topCapHeight:14)
}
self.bubbleImage.frame = CGRect(x: x, y: y, width: (width + self.msgModel.insets.left + self.msgModel.insets.right), height: (height + self.msgModel.insets.top + self.msgModel.insets.bottom))
}
//让单元格宽度始终为屏幕宽
override var frame: CGRect {
get {
return super.frame
}
set (newFrame) {
var frame = newFrame
frame.size.width = UIScreen.main.bounds.width
super.frame = frame
}
}
}
TableView
import Foundation
import UIKit
class TableView: UITableView,UITableViewDelegate,UITableViewDataSource {
//存储消息
var bubbleSection:Array<messageModel>!
//数据源,用于与 ViewController 交换数据
var chatDataSource:chatDataSourch!
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
//override覆盖 重写初始化方法
override init(frame: CGRect, style: UITableViewStyle) {
//初始化
super.init(frame: frame, style: style)
self.bubbleSection = Array<messageModel>()
self.backgroundColor = UIColor.clear
self.separatorStyle = UITableViewCellSeparatorStyle.none
self.delegate = self
self.dataSource = self
}
//重写reloadData方法
override func reloadData() {
//设置不显示滚动条
self.showsVerticalScrollIndicator = false
self.showsHorizontalScrollIndicator = false
var count = 0
if self.chatDataSource != nil {
count = self.chatDataSource.rowsForChatTable(tableView: self)
if count>0 {
for i in 0..<count {
let object = self.chatDataSource.chatTableView(tableView: self, dataForRow: i)
self.bubbleSection.append(object)
}
//按日期排序方法
bubbleSection.sort(by: {
$0.date.timeIntervalSince1970 < $1.date.timeIntervalSince1970
})
}
}
super.reloadData()
}
//区数
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if (section >= self.bubbleSection.count)
{
return 0
}
return self.bubbleSection.count
}
//用于确定单元格的高度,如果此方法实现得不对,单元格与单元格之间会错位
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let data = self.bubbleSection[indexPath.row]
return max(data.insets.top + data.view.frame.size.height + data.insets.bottom, 52)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellID = "GPLcell"
let data = self.bubbleSection[indexPath.row]
let cell = tableViewCell(data: data, reuseIdentifier: cellID)
return cell
}
}