本功能是我写的一个xmpp聊天客户端Demo的一部分,完整的代码请参考http://www.oschina.net/code/snippet_811893_37648,在此先附上一个截图:
下面介绍其实现要点,一是通过UITableView实现聊天界面,其每一行聊天信息是UITableViewCell,但是默认的UITableViewCell不能显示上图的泡泡图片,因此需要重新写一个UITableViewCell:
class MessageCell:UITableViewCell { var senderAndTimeLabel:UILabel var messageContentView:UITextView var bgImageView:UIImageView init(newStyle:UITableViewCellStyle, newReuseIdentifier:NSString) { senderAndTimeLabel = UILabel( frame:CGRectMake(10, 10, 300, 20)) bgImageView = UIImageView(frame:CGRectZero) messageContentView = UITextView() super.init(style:newStyle, reuseIdentifier:newReuseIdentifier) //日期标签 //居中显示 senderAndTimeLabel.textAlignment = .Center senderAndTimeLabel.font = UIFont.systemFontOfSize(12.0) //文字颜色 senderAndTimeLabel.textColor = UIColor.lightGrayColor() contentView.addSubview(senderAndTimeLabel) //背景图 contentView.addSubview(bgImageView) //聊天信息 messageContentView.backgroundColor = UIColor.clearColor() //不可编辑 messageContentView.editable = false; messageContentView.scrollEnabled = false; messageContentView.sizeToFit() contentView.addSubview(messageContentView) } }
每个MessageCell会有3个控件:
1、显示发送者和发送时间的标签,其字体颜色被设置为灰色,内容会根据具体的聊天信息在使用时设置。
2、一个图片,图片的属性都未设置,需要根据的聊天内容设置其大小和位置
3、一个文本框,同样文本框的大小和内容也是根据聊天内容再设置的。
第二步就是根据聊天信息设置上述3个控件:
//UITableViewDelegate协议实现 func tableView(tableView:UITableView! ,cellForRowAtIndexPath indexPath:NSIndexPath ) ->UITableViewCell{ let padding:CGFloat = 10.0 var identifier:String = "msgCell"; var cell:MessageCell? = tableView?.dequeueReusableCellWithIdentifier(identifier) as? MessageCell if (cell == nil) { cell = MessageCell(newStyle:.Subtitle ,newReuseIdentifier:identifier) } var msg:Message = messages[indexPath.row]; var textSize = CGSize(width: 260.0 ,height: 10000.0) //根据文字获取其占用的尺寸 var font:UIFont = UIFont.systemFontOfSize(18) var rect:CGRect = msg.content.boundingRectWithSize(textSize, options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [NSFontAttributeName:font], context: nil) rect.size.width += (padding/2) cell!.messageContentView.text = msg.content; cell!.accessoryType = .None; cell!.userInteractionEnabled = false; var bgImage:UIImage? //发送消息 if (msg.sender == "you") { //背景图 bgImage = UIImage(named:"BlueBubble2") //拉伸图片 bgImage = bgImage!.stretchableImageWithLeftCapWidth(20,topCapHeight:15) //设置文本框的大小,padding相当于外边框的大小 cell!.messageContentView.frame = CGRectMake(rect.origin.x+padding, rect.origin.y+padding*4, rect.size.width, rect.size.height) cell!.bgImageView.frame = CGRectMake(cell!.messageContentView.frame.origin.x - padding/2, cell!.messageContentView.frame.origin.y - padding/2 , rect.size.width + padding, rect.size.height + padding) }else { bgImage = UIImage(named:"GreenBubble2").stretchableImageWithLeftCapWidth(14, topCapHeight:15) //如果不是你发送的消息,则位置在右边 cell!.messageContentView.frame = CGRectMake(320-rect.size.width - padding-rect.origin.x, padding*4+rect.origin.y, rect.size.width, rect.size.height) cell!.bgImageView.frame = CGRectMake(cell!.messageContentView.frame.origin.x - padding/2, cell!.messageContentView.frame.origin.y - padding/2, rect.size.width + padding, rect.size.height + padding) } cell!.bgImageView.image = bgImage; cell!.senderAndTimeLabel.text = "\(msg.sender) \(msg.ctime)" return cell!; }
由注释可以看出,文本框的设置需要获得文字需要占用的尺寸,并且计算文本框占用的大小,与Object-C不同是函数:
boundingRectWithSize(textSize, options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [NSFontAttributeName:font], context: nil)
泡泡状的背景图片其实是由如下两图变化得到的:
通过stretchableImageWithLeftCapWidth(20,topCapHeight:15)函数拉伸和设置UIImageView的大小最终变为最前面效果图的形状
还有一处需要注意,就是设置MessageCell高度,类似前面的方法:
//每一行的高度 func tableView(tableView:UITableView, heightForRowAtIndexPath indexPath:NSIndexPath) -> CGFloat{ let padding:CGFloat = 20.0 var msg:Message = messages[indexPath.row]; var textSize = CGSize(width: 260.0 ,height: 10000.0) var font:UIFont = UIFont.systemFontOfSize(18) var rect:CGRect = msg.content.boundingRectWithSize(textSize, options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [NSFontAttributeName:font], context: nil) //var size = msg.content.sizeWithAttributes([NSFontAttributeName:font]) rect.size.height += padding*4 var height:CGFloat = rect.size.height < 65 ? 65 : rect.size.height; return height; }