iOS开发——UI_swift篇&TableView自定义聊天界面

TableView自定义聊天界面

1,下面是一个放微信聊天界面的消息展示列表,实现的功能有:

  • (1)消息可以是文本消息也可以是图片消息
  • (2)消息背景为气泡状图片,同时消息气泡可根据内容自适应大小
  • (3)每条消息旁边有头像,在左边表示发送方,在右边表示接收方

2,实现思路

  • (1)需要定义一个数据结构保存消息内容 MessageItem
  • (2)继承UITableViewCell实现自定义单元格,这里面放入头像和消息体
  • (3)继承UITableView实现自定义表格,通过读取数据源,进行页面的渲染
  • (4)消息体根据内容类型不同,用不同的展示方法
  • (5)每个单元格的高度需要根据内容计算出来
  • (6)数据由ViewController来提供初始化数据

3,效果图

4,代码结构

5,主要代码

(1)主页面 ViewController.swift

 1 import UIKit
 2
 3 class ViewController: UIViewController, ChatDataSource {
 4
 5     var Chats:Array<MessageItem>!
 6     var tableView:TableView!
 7
 8     override func viewDidLoad() {
 9         super.viewDidLoad()
10         // Do any additional setup after loading the view, typically from a nib.
11
12         setupChatTable()
13     }
14
15     /*创建表格及数据*/
16     func setupChatTable()
17     {
18         self.tableView = TableView(frame:CGRectMake(0, 20,
19             self.view.frame.size.width, self.view.frame.size.height - 20))
20
21         //创建一个重用的单元格
22         self.tableView!.registerClass(TableViewCell.self, forCellReuseIdentifier: "MsgCell")
23
24         var me = "xiaoming.png"
25
26         var you = "xiaohua.png"
27
28         var first =  MessageItem(body:"嘿,这张照片咋样,我周末拍的呢!", logo:me,
29             date:NSDate(timeIntervalSinceNow:-600), mtype:ChatType.Mine)
30
31
32         var second =  MessageItem(image:UIImage(named:"luguhu.jpeg")!,logo:me,
33             date:NSDate(timeIntervalSinceNow:-290), mtype:ChatType.Mine)
34
35         var third =  MessageItem(body:"太赞了,我也想去那看看呢!",logo:you,
36             date:NSDate(timeIntervalSinceNow:-60), mtype:ChatType.Someone)
37
38          var fouth =  MessageItem(body:"嗯,下次我们一起去吧!",logo:me,
39             date:NSDate(timeIntervalSinceNow:-20), mtype:ChatType.Mine)
40
41         var fifth =  MessageItem(body:"好的,一定!",logo:you,
42             date:NSDate(timeIntervalSinceNow:0), mtype:ChatType.Someone)
43
44         Chats = [first,second, third, fouth, fifth]
45
46         self.tableView.chatDataSource = self
47
48
49         self.tableView.reloadData()
50
51         self.view.addSubview(self.tableView)
52     }
53
54     override func didReceiveMemoryWarning() {
55         super.didReceiveMemoryWarning()
56         // Dispose of any resources that can be recreated.
57     }
58
59     /*返回对话记录中的全部行数*/
60     func rowsForChatTable(tableView:TableView) -> Int
61     {
62         return self.Chats.count
63     }
64
65     /*返回某一行的内容*/
66     func chatTableView(tableView:TableView, dataForRow row:Int) -> MessageItem
67     {
68         return Chats[row]
69     }
70 }

(2)消息体数据结构 MessageItem.swift

  1 import UIKit
  2
  3 //消息类型,我的还是别人的
  4 enum ChatType
  5 {
  6     case Mine
  7     case Someone
  8 }
  9
 10 class MessageItem
 11 {
 12     //头像
 13     var logo:String
 14     //消息时间
 15     var date:NSDate
 16     //消息类型
 17     var mtype:ChatType
 18     //内容视图,标签或者图片
 19     var view:UIView
 20     //边距
 21     var insets:UIEdgeInsets
 22
 23     //设置我的文本消息边距
 24     class func getTextInsetsMine() -> UIEdgeInsets
 25     {
 26         return UIEdgeInsets(top:5, left:10, bottom:11, right:17)
 27     }
 28
 29     //设置他人的文本消息边距
 30     class func getTextInsetsSomeone() -> UIEdgeInsets
 31     {
 32         return UIEdgeInsets(top:5, left:15, bottom:11, right:10)
 33     }
 34
 35     //设置我的图片消息边距
 36     class func getImageInsetsMine() -> UIEdgeInsets
 37     {
 38         return UIEdgeInsets(top:11, left:13, bottom:16, right:22)
 39     }
 40
 41     //设置他人的图片消息边距
 42     class func getImageInsetsSomeone() -> UIEdgeInsets
 43     {
 44         return UIEdgeInsets(top:11, left:13, bottom:16, right:22)
 45     }
 46
 47     //构造文本消息体
 48     convenience init(body:NSString, logo:String, date:NSDate, mtype:ChatType)
 49     {
 50         var font =  UIFont.boldSystemFontOfSize(12)
 51
 52         var width =  225, height = 10000.0
 53
 54         var atts =  NSMutableDictionary()
 55         atts.setObject(font,forKey:NSFontAttributeName)
 56
 57         var size =  body.boundingRectWithSize(CGSizeMake(CGFloat(width), CGFloat(height)),
 58             options:NSStringDrawingOptions.UsesLineFragmentOrigin, attributes:atts, context:nil)
 59
 60         var label =  UILabel(frame:CGRectMake(0, 0, size.size.width, size.size.height))
 61
 62         label.numberOfLines = 0
 63         label.lineBreakMode = NSLineBreakMode.ByWordWrapping
 64         label.text = (body.length != 0 ? body : "")
 65         label.font = font
 66         label.backgroundColor = UIColor.clearColor()
 67
 68         var insets:UIEdgeInsets =  (mtype == ChatType.Mine ?
 69             MessageItem.getTextInsetsMine() : MessageItem.getTextInsetsSomeone())
 70
 71         self.init(logo:logo, date:date, mtype:mtype, view:label, insets:insets)
 72     }
 73
 74     //可以传入更多的自定义视图
 75     init(logo:String, date:NSDate, mtype:ChatType, view:UIView, insets:UIEdgeInsets)
 76     {
 77         self.view = view
 78         self.logo = logo
 79         self.date = date
 80         self.mtype = mtype
 81         self.insets = insets
 82     }
 83
 84     //构造图片消息体
 85     convenience init(image:UIImage, logo:String,  date:NSDate, mtype:ChatType)
 86     {
 87         var size = image.size
 88         //等比缩放
 89         if (size.width > 220)
 90         {
 91             size.height /= (size.width / 220);
 92             size.width = 220;
 93         }
 94         var imageView = UIImageView(frame:CGRectMake(0, 0, size.width, size.height))
 95         imageView.image = image
 96         imageView.layer.cornerRadius = 5.0
 97         imageView.layer.masksToBounds = true
 98
 99         var insets:UIEdgeInsets =  (mtype == ChatType.Mine ?
100             MessageItem.getImageInsetsMine() : MessageItem.getImageInsetsSomeone())
101
102         self.init(logo:logo,  date:date, mtype:mtype, view:imageView, insets:insets)
103     }
104 }

(3)表格数据协议 ChatDataSource.swift

 1 import Foundation
 2
 3 /*
 4   数据提供协议
 5 */
 6 protocol ChatDataSource
 7 {
 8     /*返回对话记录中的全部行数*/
 9     func rowsForChatTable( tableView:TableView) -> Int
10     /*返回某一行的内容*/
11     func chatTableView(tableView:TableView, dataForRow:Int)-> MessageItem
12 }

(4)自定义表格 TableView.swift

  1 import UIKit
  2
  3 class TableView:UITableView,UITableViewDelegate, UITableViewDataSource
  4 {
  5     //用于保存所有消息
  6     var bubbleSection:Array<MessageItem>!
  7     //数据源,用于与 ViewController 交换数据
  8     var chatDataSource:ChatDataSource!
  9
 10     required init(coder aDecoder: NSCoder) {
 11
 12         super.init(coder: aDecoder)
 13     }
 14
 15     override init(frame:CGRect)
 16     {
 17         self.bubbleSection = Array<MessageItem>()
 18
 19         super.init(frame:frame,  style:UITableViewStyle.Grouped)
 20
 21         self.backgroundColor = UIColor.clearColor()
 22
 23         self.separatorStyle = UITableViewCellSeparatorStyle.None
 24         self.delegate = self
 25         self.dataSource = self
 26
 27
 28     }
 29
 30     override func reloadData()
 31     {
 32
 33         self.showsVerticalScrollIndicator = false
 34         self.showsHorizontalScrollIndicator = false
 35
 36         var count =  0
 37         if ((self.chatDataSource != nil))
 38         {
 39             count = self.chatDataSource.rowsForChatTable(self)
 40
 41             if(count > 0)
 42             {
 43
 44                 for (var i = 0; i < count; i++)
 45                 {
 46
 47                     var object =  self.chatDataSource.chatTableView(self, dataForRow:i)
 48                     bubbleSection.append(object)
 49
 50                 }
 51
 52                 //按日期排序方法
 53                 bubbleSection.sort({$0.date.timeIntervalSince1970 < $1.date.timeIntervalSince1970})
 54             }
 55         }
 56         super.reloadData()
 57     }
 58
 59     //第一个方法返回分区数,在本例中,就是1
 60     func numberOfSectionsInTableView(tableView:UITableView)->Int
 61     {
 62         return 1
 63     }
 64
 65     //返回指定分区的行数
 66     func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
 67     {
 68         if (section >= self.bubbleSection.count)
 69         {
 70             return 1
 71         }
 72
 73         return self.bubbleSection.count+1
 74     }
 75
 76     //用于确定单元格的高度,如果此方法实现得不对,单元格与单元格之间会错位
 77     func tableView(tableView:UITableView,heightForRowAtIndexPath indexPath:NSIndexPath) -> CGFloat
 78     {
 79
 80         // Header
 81         if (indexPath.row == 0)
 82         {
 83             return 30.0
 84         }
 85
 86         var data =  self.bubbleSection[indexPath.row - 1]
 87
 88         return max(data.insets.top + data.view.frame.size.height + data.insets.bottom, 52)
 89     }
 90
 91     //返回自定义的 TableViewCell
 92     func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)
 93         -> UITableViewCell
 94     {
 95
 96         var cellId = "MsgCell"
 97         if(indexPath.row > 0)
 98         {
 99             var data =  self.bubbleSection[indexPath.row-1]
100
101             var cell =  TableViewCell(data:data, reuseIdentifier:cellId)
102
103             return cell
104         }
105         else
106         {
107
108             return UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: cellId)
109         }
110     }
111 }

(5)自定义单元格 TableViewCell.swift

  1 import UIKit
  2
  3 class TableViewCell:UITableViewCell
  4 {
  5     //消息内容视图
  6     var customView:UIView!
  7     //消息背景
  8     var bubbleImage:UIImageView!
  9     //头像
 10     var avatarImage:UIImageView!
 11     //消息数据结构
 12     var msgItem:MessageItem!
 13
 14     required init(coder aDecoder: NSCoder) {
 15
 16         super.init(coder: aDecoder)
 17     }
 18
 19     //- (void) setupInternalData
 20     init(data:MessageItem, reuseIdentifier cellId:String)
 21     {
 22         self.msgItem = data
 23         super.init(style: UITableViewCellStyle.Default, reuseIdentifier:cellId)
 24         rebuildUserInterface()
 25     }
 26
 27     func rebuildUserInterface()
 28     {
 29
 30         self.selectionStyle = UITableViewCellSelectionStyle.None
 31         if (self.bubbleImage == nil)
 32         {
 33             self.bubbleImage = UIImageView()
 34             self.addSubview(self.bubbleImage)
 35
 36         }
 37
 38         var type =  self.msgItem.mtype
 39         var width =  self.msgItem.view.frame.size.width
 40
 41         var height =  self.msgItem.view.frame.size.height
 42
 43         var x =  (type == ChatType.Someone) ? 0 : self.frame.size.width - width -
 44             self.msgItem.insets.left - self.msgItem.insets.right
 45
 46         var y:CGFloat =  0
 47         //显示用户头像
 48         if (self.msgItem.logo != "")
 49         {
 50
 51             var logo =  self.msgItem.logo
 52
 53             self.avatarImage = UIImageView(image:UIImage(named:(logo != "" ? logo : "noAvatar.png")))
 54
 55             self.avatarImage.layer.cornerRadius = 9.0
 56             self.avatarImage.layer.masksToBounds = true
 57             self.avatarImage.layer.borderColor = UIColor(white:0.0 ,alpha:0.2).CGColor
 58             self.avatarImage.layer.borderWidth = 1.0
 59
 60             //别人头像,在左边,我的头像在右边
 61             var avatarX =  (type == ChatType.Someone) ? 2 : self.frame.size.width - 52
 62
 63             //头像居于消息底部
 64             var avatarY =  height
 65             //set the frame correctly
 66             self.avatarImage.frame = CGRectMake(avatarX, avatarY, 50, 50)
 67             self.addSubview(self.avatarImage)
 68
 69
 70             var delta =  self.frame.size.height - (self.msgItem.insets.top + self.msgItem.insets.bottom
 71                 + self.msgItem.view.frame.size.height)
 72             if (delta > 0)
 73             {
 74                 y = delta
 75             }
 76             if (type == ChatType.Someone)
 77             {
 78                 x += 54
 79             }
 80             if (type == ChatType.Mine)
 81             {
 82                 x -= 54
 83             }
 84         }
 85
 86         self.customView = self.msgItem.view
 87         self.customView.frame = CGRectMake(x + self.msgItem.insets.left, y
 88             + self.msgItem.insets.top, width, height)
 89
 90         self.addSubview(self.customView)
 91
 92         //如果是别人的消息,在左边,如果是我输入的消息,在右边
 93         if (type == ChatType.Someone)
 94         {
 95             self.bubbleImage.image =
 96                 UIImage(named:("yoububble.png"))!.stretchableImageWithLeftCapWidth(21,topCapHeight:14)
 97
 98         }
 99         else {
100             self.bubbleImage.image =
101                 UIImage(named:"mebubble.png")!.stretchableImageWithLeftCapWidth(15, topCapHeight:14)
102         }
103         self.bubbleImage.frame = CGRectMake(x, y, width + self.msgItem.insets.left
104             + self.msgItem.insets.right, height + self.msgItem.insets.top + self.msgItem.insets.bottom)
105     }
106 }

(1)消息按天分组展示

(2)增加消息发送框,可以发送和展示消息

时间: 2024-12-25 12:06:36

iOS开发——UI_swift篇&TableView自定义聊天界面的相关文章

iOS开发——UI_swift篇&amp;TableView实现页眉和页脚

TableView实现页眉和页脚 UITableView具有var tableHeaderView:UIView?属性和var tableFooterView:UIView?属性,可以通过给其赋值来创建列表TableView的页眉和页脚. 效果图如下: 代码如下: 1 import UIKit 2 3 class ViewController: UIViewController,UITableViewDelegate, 4 UITableViewDataSource,UIGestureRecog

iOS开发项目篇—28自定义UITextView

iOS开发项目篇—28自定义UITextView 一.简单说明 1.要实现的效果 2.分析 (1)UITextField 1.最多只能输入一行文字 2.能设置提醒文字(placehoder) 3.不具备滚动功能 (2)UITextView 1.能输入N行文字(N>0) 2.不能设置提醒文字(没有placehoder属性) 3.具备滚动功能 需求:技能输入多行文字,又具备文字提醒功能. 这里选择自定义一个类,让其继承自UITextView类,为其添加一个设置文字提醒的功能. 二.实现 自定义UI控

iOS开发项目篇—29自定义工具条

iOS开发项目篇—29自定义工具条 一.简单说明 1.实现效果: 2.实现思路: (1)尝试: 1 //添加子控件 2 -(void)setupTextView 3 { 4 //1.创建输入控件 5 YYTextView *textView=[[YYTextView alloc]init]; 6 //设置frame 7 textView.frame=self.view.bounds; 8 [self.view addSubview:textView]; 9 self.textView=textV

iOS开发项目篇—27自定义UITabBar

iOS开发项目篇—27自定义UITabBar 一.自定义 思路: (1)新建一个继承自UITabBar的类,自定义一个UITabBar (2)用自定义的UITabBar换掉系统的UItabBar(使用了KVC) (3)监听控制器的切换,只要控制器一切换,就调用代理方法强制重新布局子控件(内部会调用layoutSubviews). YYTabBar.m文件代码: 1 // 2 // YYTabBar.m 3 // 4 5 #import "YYTabBar.h" 6 7 @interfa

iOS开发多线程篇 11 —自定义NSOperation

iOS开发多线程篇—自定义NSOperation 一.实现一个简单的tableView显示效果 实现效果展示: 代码示例(使用以前在主控制器中进行业务处理的方式) 1.新建一个项目,让控制器继承自UITableViewController. 1 // 2 // YYViewController.h 3 // 01-自定义Operation 4 // 5 // Created by apple on 14-6-26. 6 // Copyright (c) 2014年 itcase. All rig

IOS开发UI篇之──自定义UIActionSheet

转载自:http://www.cnblogs.com/pengyingh/articles/2343200.html UIActionSheet类系IOS开发中实现警告框的重要的类,而在好多应用中,都对它进行了扩展,今天介绍一下自定义风格的UIActionSheet 一.自定义CustomActionSheet类 CustomActionSheet类继承UIActionSheet,具体的实现如下所示: 1)CustomActionSheet.h头文件 #import <Foundation/Fo

iOS开发UI篇—Quartz2D(自定义UIImageView控件)

一.实现思路 Quartz2D最大的用途在于自定义View(自定义UI控件),当系统的View不能满足我们使用需求的时候,自定义View. 使用Quartz2D自定义View,可以从模仿系统的ImageView的使用开始. 需求驱动开发:模仿系统的imageview的使用过程 1.创建 2.设置图片 3.设置frame 4.把创建的自定义的view添加到界面上(在自定义的View中,需要一个image属性接收image图片参数->5). 5.添加一个image属性(接下来,拿到image之后,应

iOS开发——UI_swift篇&amp;UITableView实现索引功能

UITableView实现索引功能 像iOS中的通讯录,通过点击联系人表格右侧的字母索引,我们可以快速定位到以该字母为首字母的联系人分组. 要实现索引,我们只需要两步操作: (1)实现索引数据源代理方法 (2)响应点击索引触发的代理事件 效果图如下: 代码如下: 1 import UIKit 2 3 class ViewController: UIViewController , UITableViewDelegate, UITableViewDataSource{ 4 5 var tableV

iOS开发——UI_swift篇&amp;UITableView实现单元格展开与隐藏

UITableView实现单元格展开与隐藏 下面是一个列表单元格cell的折叠展开效果的demo. 当点击单元格时会展开该单元格,便于显示一些详情什么的.点击其他单元格原来的会关闭,同时有动画效果. 效果如如下:   代码如下: 1 import UIKit 2 3 class ViewController: UIViewController,UITableViewDelegate, 4 UITableViewDataSource { 5 6 var tableView:UITableView?