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 ...
随机推荐
- 游戏设计模式:Subclass Sandbox模式,以及功能方法集的设计思考
书中总结出这种 Subclass Sandbox 的设计模式 Game Design Patterns: Subclass Sandbox 这种模式要点有两点: 在基类中实现各种功能性方法供子类调用 ...
- [CODEVS2603]公路修建
题目描述 某国有n个城市,它们互相之间没有公路相通,因此交通十分不便.为解决这一“行路难”的问题,政府决定修建公路.修建公路的任务由各城市共同完成. 修建工程分若干轮完成.在每一轮中,每个城市选 ...
- private
成员变量私有化的好处在于可以强制加强面向对象和封装的概念,一个面向对象的系统更加关注行为,而不是数据,所以应该通过发送消息来获得数据,也应该实习细节的封装
- CSAPP(1):数字的计算机表示——课后题
2.65 int even_ones(unsigned x) 要求:return 1 when x contains an even number of 1s; 0 otherwise. 假设int ...
- Java相关书籍推荐
Java从入门到精通(第3版 附光盘) 作 者 明日科技 编 出 版 社 清华大学出版社 出版时间 2012-08-01 版 次 3 页 数 564 印刷时间 2012- ...
- 直接调用系统Camera
关键思路: 初始化 组件: 创建并启动拍照intent: 使用回调函数onActivityResult()处理图像. 关键代码: 初始化 组件: takePicBtn = (Button) findV ...
- JSP学习笔记(一)
注释: 1.单行注释<!-- -->或者// <%@ page language="java" import="java.util.*" co ...
- 软件工程个人作业——Agile Software Development读后感
昨天利用了半天的时间看了下老师给的网页下的8篇文章和一段宣言,将感悟整理为下面的一篇博客. 首先先介绍一下这个网页.记得我们上学期上过一门课叫做面向对象建模方法,在这门课上刘超老师极力推荐的一本教材— ...
- 最大连续子数组问题-homework-01
1)先写我的 github 的介绍: github 的域名:http://www.github.com/zhuifeng1022 登入 github 大概是下面的视图: 按照助教的方法:我已经建好了代 ...
- WinJS.Binding.List与kendo.data.ObservableArray
avalon0.8一个最大目标是实现对数组的深层监控,可是面临的困难重重,至今还没有什么起色.于是看一下其他两个MVVM框架的做法(knockout, emberjs, angular都不能监听家庭数 ...