zoukankan      html  css  js  c++  java
  • Swift

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

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

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

    3,效果图
      

    4,代码结构
      

    5,主要代码
    (1)主页面 ViewController.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
    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 


    7,功能改进版下载:WeiXinChart_advance.zip
    (1)消息按天分组展示
    (2)增加消息发送框,可以发送和展示消息

       

  • 相关阅读:
    Bootstrap 2.2.2 的新特性
    Apache POI 3.9 发布,性能显著提升
    SQL Relay 0.48 发布,数据库中继器
    ProjectForge 4.2.0 发布,项目管理系统
    红帽企业 Linux 发布 6.4 Beta 版本
    红薯 快速的 MySQL 本地和远程密码破解
    MariaDB 宣布成立基金会
    Percona XtraBackup 2.0.4 发布
    Rocks 6.1 发布,光盘机群解决方案
    精通Servlet研究,HttpServlet的实现追究
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/4838230.html
Copyright © 2011-2022 走看看