聊天界面之气泡文本cell(一)

在实现qq聊天界面的过程中,使用UITableViewCell碰到了不少问题,这里还是记录一下以免遗忘。

 

气泡聊天cell的实现,网上最多的方法还是:

1.手动计算设置frame的值,文本的size使用boundingRectWithSize函数动态计算

2.气泡的实现,拉伸使用resizableImageWithCapInsets函数,还需要设置文本UILabel的frame在气泡之内

因为后来发现tableView在绘制cell时是先询问高度,再询问cell,可是询问高度时cell还未计算,如果先计算一遍高度的话效率上又不划算,

这种方案多少还是不完善,最后也未采用,所以直接贴出代码作为参考。

class ChatTableViewCell: UITableViewCell {
    
    @IBOutlet weak var bubbleImage: UIImageView!
    @IBOutlet weak var time: UILabel!
    @IBOutlet weak var icon: UIImageView!
    @IBOutlet weak var content: UILabel!
    
    var height:CGFloat!
    
    class func initChatCell(tableView:UITableView,message:TextMessage,iconname:String) -> ChatTableViewCell?{
        
        var t:UITableViewCell? = tableView.dequeueReusableCellWithIdentifier("ChatTableViewCell")
        
        if t == nil{
            t = NSBundle.mainBundle().loadNibNamed("ChatTableViewCell", owner: nil, options: nil).first as? UITableViewCell
        }
        let cell:ChatTableViewCell = t as! ChatTableViewCell
       
        // 屏幕的宽度
        let screenW = UIScreen.mainScreen().bounds.width
        let paddingSize:CGFloat = 5
        let timeHided = false

        if timeHided{
           cell.time.frame = CGRectMake(0,0, 0, 0)
           cell.time.hidden = true
        }else{
            cell.time.textAlignment = NSTextAlignment.Center
            cell.time.textColor = UIColor.darkGrayColor()
            cell.time.font = UIFont.systemFontOfSize(13)
            cell.time.text = message.time
            cell.time.frame = CGRectMake(0,paddingSize,screenW,20)
        }
        cell.time.layoutIfNeeded()
        
        let timeH = cell.time.frame.maxY + paddingSize
        let iconSize:CGFloat = 40
        let bubble_insets = (message.role == Role.Me ? UIEdgeInsetsMake(15,20,15,23):UIEdgeInsetsMake(15,23,15,20))
        let iconExtendWith = iconSize+paddingSize
        
        
        let textString = NSString(string: message.text ?? "")
        let size = CGSizeMake(screenW-iconExtendWith*2-bubble_insets.left-bubble_insets.right, CGFloat(MAXFLOAT))
        let attributes = [NSFontAttributeName: UIFont.systemFontOfSize(15)]
        let textSize = textString.boundingRectWithSize(size, options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: attributes, context: nil)
        let bubbleWidth  =  textSize.width+bubble_insets.left+bubble_insets.right
        let bubbleHeight =  textSize.height+bubble_insets.top+bubble_insets.bottom
        var iconF:CGRect
        var bubbleF:CGRect
        var contentF:CGRect
        var bgImage:UIImage
        if message.role == Role.Me{
            iconF = CGRectMake(screenW-paddingSize-iconSize, timeH+bubble_insets.top*0.7,iconSize, iconSize)
            
            bubbleF = CGRectMake(iconF.origin.x-bubbleWidth-paddingSize,timeH,bubbleWidth,bubbleHeight)
            bgImage = UIImage(named:"chat_send_nor@2x")!
        }else{
            iconF = CGRectMake(paddingSize, timeH+bubble_insets.top*0.7,iconSize, iconSize)
            
            bubbleF = CGRectMake(iconF.maxX+paddingSize,timeH,bubbleWidth,bubbleHeight)
            bgImage = UIImage(named:"chat_recive_nor@2x")!
        }
        contentF = CGRectMake(bubbleF.origin.x+bubble_insets.left, bubbleF.origin.y+bubble_insets.top, textSize.width, textSize.height)
        
        cell.icon.image = UIImage(named:iconname)
        cell.icon.frame = iconF
        cell.icon.layoutIfNeeded()
        
        cell.content.font = UIFont.systemFontOfSize(15)
        cell.content.numberOfLines = 0
        cell.content.lineBreakMode = .ByWordWrapping
        cell.content.text = message.text
        cell.content.frame = contentF
        cell.content.layoutIfNeeded()
        
        let H = floor(bgImage.size.height*0.5)
        let W = floor(bgImage.size.width*0.5)
        let insets = UIEdgeInsetsMake(H, W, bgImage.size.height-H-1, bgImage.size.width-W-1)
        cell.bubbleImage.image = bgImage.resizableImageWithCapInsets(insets)
        cell.bubbleImage.frame = bubbleF
        cell.bubbleImage.layoutIfNeeded()
    
        cell.layoutIfNeeded()//需要在xib中禁用autolayout,layoutIfNeeded否则失效,cell第一次会按xib中的布局显示
        cell.height = max(cell.bubbleImage.frame.maxY,cell.icon.frame.maxY)
        
        return t as? ChatTableViewCell
    }

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
        self.backgroundColor = UIColor.whiteColor()
    }

    override func setSelected(selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }
//    override func layoutSubviews() {
//        super.layoutSubviews()
//    }
}

  

cell是在xib中实现的,需要注意的是:

1.需要先拖bubbleImage,再拖uilabel,因为文字要显示在气泡之上。否则的话文字会被气泡覆盖掉

2.需要在 xib中禁用autolayout,否则好像手动设置的frame,调用layoutIfNeeded不起作用。而约束又未设置,cell就会以初始布局显示。

 

附上目前使用的三种类型的消息的定义:

//
//  Message.swift
//  OrayTalk
//
//  Created by 梅利健 on 16/6/4.
//  Copyright © 2016年 meilijian. All rights reserved.
//

import Foundation

public enum Role:Int {
    case Me
    case Other
}

class BaseMessage:NSObject{
    var time:String!
    var text:String!
    override init() {
        super.init()
    }
    
    init(time:String,text:String) {
        self.time = time
        self.text = text
    }
}

class TextMessage:BaseMessage{

    var role:Role = Role.Me

    class func messageWithDic(dic:[String:AnyObject],role:Role) -> TextMessage{
        
        let message = TextMessage()
        
        message.setValuesForKeysWithDictionary(dic)
        message.role = role
        return message
        
    }
    override init() {
        super.init()
    }
    init(time:String,text:String,role:Role) {
        super.init(time: time,text: text)
        self.role = role
    }
}

class TipMessage: BaseMessage {
    
}

class ProgressMessage:BaseMessage{
    var role:Role = Role.Me
    var total: UInt64 = 0
    var transfered: UInt64 = 0
    var lastdate:NSDate =  NSDate()
    var lasttransfered: UInt64 = 0
    var speed:Double = 0
    init(time:String,text:String,role:Role) {
        super.init(time: time,text: text)
        self.role = role
    }
    
    var SpeedDescription:String{
        get{
            if speed >= 1024*1024{
                return NSString(format: "%0.2fM/s", speed/(1024*1024)) as String
            }
            else if speed >= 1024{
                return NSString(format: "%0.2fK/s", speed/(1024)) as String
            }
            else if speed >= 0{
                return NSString(format: "%0.2fB/s", speed) as String
            }
            else{
                return NSString(format: "%0.2fB/s", 0) as String
            }
        }
    }
}

  

posted @ 2016-09-03 10:10  mlj318  阅读(495)  评论(0编辑  收藏  举报