qq聊天界面模拟

模拟简化的qq聊天的界面
需要注意的有:计算字符串所占的大小,扩展的使用,图片的 stretchableImageWithLeftCapWidth方法的使用,通知的使用,键盘的通知事件的使用, TableView的一些方法和属性
代码

数据模型类
//
//  Message.swift
//  QQ
//
//  Created by zhang on 16/1/7.
//  Copyright © 2016年 jin. All rights reserved.
//
//时间lable字体大小
let timeFontSize:CGFloat = 15
//文本lable字体大小
let textFontSize:CGFloat = 16
//按钮内边距
let buttonEdgeInsets:CGFloat = 20
import UIKit
class Message: NSObject {
    var text:NSString!
    var time:NSString!
    var type:NSNumber!
        {
        //变量发生改变之后执行这个方法
        didSet
        {
            if self.type == 0
            {
                self.icon = "me"
            }
            else
            {
                self.icon = "other"
            }
        }
    }
    var hiddenTime:Bool = true
    var icon:String!
    convenience init(dic:[String : AnyObject]) {
        self.init()
        self.setValuesForKeysWithDictionary(dic)
    }
}
cell位置信息类
//
//  MessageFrame.swift
//  QQ
//
//  Created by zhang on 16/1/7.
//  Copyright © 2016年 jin. All rights reserved.
//

import UIKit

class MessageFrame: NSObject {
    let iconFrame:CGRect
    let timeFrame:CGRect
    let textFrame:CGRect
    let cellHeight:CGFloat
    let message:Message
    //快速实例话的方法
    class func instanceWithFile()->[MessageFrame]
    {
        let path = NSBundle.mainBundle().pathForResource("messages", ofType: "plist")
        let data = NSArray(contentsOfFile: path!)
        var messageFrames:[MessageFrame] = []
        //这个变量用于记录上一个消息时间,用这个判断当前messageCell是否显示时间lable
        var flag:NSString = ""
        for var i = 0;i < data?.count;i++
        {
            let message = Message(dic: data![i] as! [String : AnyObject])
            //判断是否显示时间
            if flag.isEqualToString(message.time as String)
            {
                message.hiddenTime = false
            }
            flag = message.time
            messageFrames.append(MessageFrame.init(message: message))
        }
        return messageFrames
    }
    convenience init(message:Message) {
        let margin:CGFloat = 10
        //计算头像frame
        var iconFrame:CGRect = CGRect.zero
        let iconW:CGFloat = 50
        let iconH:CGFloat = 50
        var iconX:CGFloat = margin
        let iconY:CGFloat = margin
        //当是自己的消息的时候,更改坐标位置
        if message.type == 0
        {
            iconX = UIScreen.mainScreen().bounds.size.width - margin - iconW
        }
        iconFrame = CGRectMake(iconX, iconY, iconW, iconH)
        //时间lable
        var timeFrame:CGRect = CGRect.zero
        if message.hiddenTime
        {
            let timeW = UIScreen.mainScreen().bounds.size.width
            //计算文字所需要的大小
            let timeH = message.time.boundingRectWithSize(CGSizeMake(CGFloat.max, CGFloat.max), options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [NSFontAttributeName:UIFont.systemFontOfSize(timeFontSize)], context: nil).size.height
            timeFrame = CGRectMake(0, 0, timeW, timeH)
        }
        //消息Button
        //计算消息文本需要的大小
        let textSize = message.text.boundingRectWithSize(CGSize(width: UIScreen.mainScreen().bounds.size.width - (iconFrame.size.width * 2) - (margin * 4),height: CGFloat.max), options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [NSFontAttributeName:UIFont.systemFontOfSize(textFontSize)], context: nil).size
        var textX = CGRectGetMaxX(iconFrame) + margin
        let textY = CGRectGetMaxY(timeFrame) + margin
        //当是自己的消息的时候,更改横坐标
        if message.type == 0
        {
            textX = iconFrame.origin.x - textSize.width - margin - (buttonEdgeInsets * 2)
        }
        //因为设置了Button内边距,所以需要加上内边距
        let textFrame = CGRectMake(textX, textY, textSize.width + (buttonEdgeInsets * 2), textSize.height + 40)
        //cell高度
        let cellHeight = (CGRectGetMaxY(textFrame) > CGRectGetMaxY(iconFrame) ? CGRectGetMaxY(textFrame) : CGRectGetMaxY(iconFrame)) + margin
        //执行构造方法
        self.init(iconFrame:iconFrame,timeFrame:timeFrame,textFrame:textFrame,cellHeight:cellHeight,message:message)
    }
    init(iconFrame:CGRect,timeFrame:CGRect,textFrame:CGRect,cellHeight:CGFloat,message:Message) {
        self.iconFrame = iconFrame
        self.timeFrame = timeFrame
        self.textFrame = textFrame
        self.cellHeight = cellHeight
        self.message = message
    }
}
自定义的cell模型类
//
//  MessageCell.swift
//  QQ
//
//  Created by zhang on 16/1/7.
//  Copyright © 2016年 jin. All rights reserved.
//

import UIKit

class MessageCell: UITableViewCell {

    var messageFrame:MessageFrame!
        {
        didSet
        {
            self.assignSubViewsContent()
            self.assignSubViewsFrame()
        }
    }
    var iconView:UIImageView!
    var timeView:UILabel!
    var textView:UIButton!
    //便捷构造器
    class func instanceWithTableView(tableView:UITableView)->MessageCell
    {
        let identifier = "qqcell"
        var cell = tableView.dequeueReusableCellWithIdentifier(identifier)
        if cell == nil
        {
            cell = MessageCell(style: UITableViewCellStyle.Default, reuseIdentifier: identifier)
        }
        let temp = cell as! MessageCell
        return temp
    }

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        //设置头像
        self.iconView = UIImageView()
        self.iconView.layer.cornerRadius = 25
        self.iconView.layer.masksToBounds = true
        //设置时间
        self.timeView = UILabel()
        self.timeView.font = UIFont.systemFontOfSize(timeFontSize)
        self.timeView.textAlignment = NSTextAlignment.Center
        //设置内容
        self.textView = UIButton()
        self.textView.titleLabel?.numberOfLines = 0
        self.textView.titleLabel?.font = UIFont.systemFontOfSize(textFontSize)
        self.textView.setTitleColor(UIColor.blackColor(), forState: UIControlState.Normal)
        self.textView.titleEdgeInsets = UIEdgeInsets(top: buttonEdgeInsets, left: buttonEdgeInsets, bottom: buttonEdgeInsets, right: buttonEdgeInsets)
        //添加进父控件
        self.addSubview(self.iconView)
        self.addSubview(self.timeView)
        self.addSubview(self.textView)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    //给子控件赋值
    func assignSubViewsContent()
    {
        self.iconView.image = UIImage(imageLiteral: self.messageFrame.message.icon)
        self.timeView.text = self.messageFrame.message.time as String
        self.textView.setTitle(self.messageFrame.message.text as String, forState: UIControlState.Normal)
        //好友和自己发送的图片是不一样的,这例做下处理
        var normalImageName = ""
        var higlightedImageName = ""
        if self.messageFrame.message.type == 0
        {
            normalImageName = "chat_send_nor"
            higlightedImageName = "chat_send_press_pic"
        }
        else
        {
            normalImageName = "chat_recive_nor"
            higlightedImageName = "chat_recive_press_pic"
        }
        //实例化图片对象并调用扩展的方法的到需要的图片
        let normalImage = UIImage(imageLiteral: normalImageName).changeImage()
        let highlightedImage = UIImage(imageLiteral: higlightedImageName).changeImage()
        //设置不同状态的背景图片
        self.textView.setBackgroundImage(normalImage, forState: UIControlState.Normal)
        self.textView.setBackgroundImage(highlightedImage, forState: UIControlState.Highlighted)
        //清除当前cell背景颜色
        self.backgroundColor = UIColor.clearColor()
        //设置消息主题内容
        self.textView.setTitle(self.messageFrame.message.text as String, forState: UIControlState.Highlighted)

    }
    //设置位置
    func assignSubViewsFrame()
    {
        self.iconView.frame = self.messageFrame.iconFrame
        self.timeView.frame = self.messageFrame.timeFrame
        self.textView.frame = self.messageFrame.textFrame
    }
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

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

        // Configure the view for the selected state
    }

}
扩展image
//
//  ImageExtension.swift
//  QQ
//
//  Created by admin on 16/1/8.
//  Copyright © 2016年 jin. All rights reserved.
//

import Foundation
import UIKit
//扩展 UIImage
extension UIImage
{
    func changeImage()->UIImage
    {
        //这个方法处理之后的图片在改变大小的时候边缘不会变化
        return self.stretchableImageWithLeftCapWidth(Int(self.size.width / 2), topCapHeight: Int(self.size.height / 2))
    }
}
最后就是在控制器中的调用了
//
//  ViewController.swift
//  QQ
//
//  Created by zhang on 16/1/7.
//  Copyright © 2016年 jin. All rights reserved.
//

import UIKit

class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate,UITextFieldDelegate {
    lazy var messageFrames:[MessageFrame] = MessageFrame.instanceWithFile()
    @IBOutlet var sendMessageView: UIView!
    @IBOutlet weak var tableView: UITableView!
    override func viewDidLoad() {
        super.viewDidLoad()
        //去掉cell的分割线
        self.tableView.separatorStyle = UITableViewCellSeparatorStyle.None
        self.tableView.allowsSelection = false
        //设置背景色
        self.tableView.backgroundColor = UIColor(red: 125/255, green: 125/255, blue: 125/255, alpha: 1)
        // Do any additional setup after loading the view, typically from a nib.
        //订阅键盘位置改变的通知
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardChange:", name: UIKeyboardWillChangeFrameNotification, object: nil)
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
        //
    }
    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.messageFrames.count
    }
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = MessageCell.instanceWithTableView(self.tableView)
        cell.messageFrame = self.messageFrames[indexPath.row]
        return cell
    }
    func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return self.messageFrames[indexPath.row].cellHeight
    }
    func tableView(tableView: UITableView, willSelectRowAtIndexPath indexPath: NSIndexPath) -> NSIndexPath? {
        return nil
    }
    // table代理方法
    func scrollViewDidScroll(scrollView: UIScrollView) {
        self.view.endEditing(true)
    }
    func keyboardChange(not:NSNotification)
    {
        //键盘位置没有发生变化的时候的位置信息,注意这里的转换
//        let beginRect = not.userInfo!["UIKeyboardFrameEndUserInfoKey"]!.CGRectValue
        //也可以直接取得,不过是一个可选类型
        let beginRect = not.userInfo![UIKeyboardFrameEndUserInfoKey]!.CGRectValue
        //键盘位置没有发生变化后的位置信息
        let endRect = not.userInfo!["UIKeyboardFrameBeginUserInfoKey"]!.CGRectValue
        let y = beginRect.origin.y - endRect.origin.y
        //动画效果,注意这里的类型转换
        UIView.animateWithDuration(NSTimeInterval(not.userInfo![UIKeyboardAnimationDurationUserInfoKey]!.floatValue), animations: {
            self.view.transform = CGAffineTransformTranslate(self.view.transform, 0, y)
        })
    }
    //文章本框键盘发送方法
    func textFieldShouldReturn(textField: UITextField) -> Bool {
        self.sendMessage(textField.text!, type: 0)
        //使用dispatch延时发送恢复消息
        let minseconds = 2 * Double(NSEC_PER_SEC)
        let dtime = dispatch_time(DISPATCH_TIME_NOW, Int64(minseconds))
        dispatch_after(dtime, dispatch_get_main_queue(), {
            self.sendMessage("哈哈哈",type: 1)
        })
        return true
    }
    //发送消息
    func sendMessage(text:NSString,type:NSNumber)
    {
        //初始化信息数据
        let message = Message()
        message.text = text
        message.type = type
        //获取时间
        let data = NSDate()
        let dataFormat = NSDateFormatter()
        dataFormat.dateFormat = "HH:mm"
        message.time = dataFormat.stringFromDate(data)
        //判断是否显示时间 lable
        if message.time.isEqualToString((self.messageFrames.last?.message.time)! as String)
        {
            message.hiddenTime = false
        }
        //添加进数据来源数组
        self.messageFrames.append(MessageFrame.init(message: message))
        //获得消息的 indexPath
        let indexPath = NSIndexPath(forRow: self.messageFrames.count - 1, inSection: 0)
        //插入cell
        self.tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Fade)
        //动画效果
        UIView.animateWithDuration(2, animations: {
            //滚动到当前发送的信息位置
            self.tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: UITableViewScrollPosition.Bottom, animated: true)
        })

    }
}

标签: swift, ios控件

添加新评论