美文网首页聊天功能设计
聊天功能(四)--创建ChatViewController

聊天功能(四)--创建ChatViewController

作者: Mage | 来源:发表于2018-06-07 12:04 被阅读14次

上一篇将所有需要使用的Cell都已经创建成功.接下来编写ChatViewController和ChatTableView.

一、ChatTableView.swift

ChatTableView只是简单的将继承DataSource,并使用FDTemplateLayoutCell自适应Cell的高度。关于Reloadable,会在下一篇文章中介绍。

import UIKit
import UITableView_FDTemplateLayoutCell

extension UITableView {
    func register(identifier: String){
        self.register(UINib.init(nibName: identifier, bundle: nil), forCellReuseIdentifier: identifier)
    }
}

class ChatTableView: UITableView, Reloadable {
    
    var reloadTableView: UITableView {return self}
    var models: [Message] = []
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        
        self.dataSource = self
        registerTableViewCell()
    }

    func registerTableViewCell(){
            self.register(ChatTextCell.self, forCellReuseIdentifier: ChatTextCell.identifier)
            self.register(ChatImageCell.self, forCellReuseIdentifier: ChatImageCell.identifier)
            self.register(ChatVoiceCell.self, forCellReuseIdentifier: ChatVoiceCell.identifier)
            self.register(ChatSystemCell.self, forCellReuseIdentifier: ChatSystemCell.identifier)
    }
    struct xixi { static var isScrollBottom: Bool = false }
    deinit {
        xixi.isScrollBottom = false
    }
}

extension ChatTableView: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        //只在初始化的时候执行
        DispatchQueue.once(&xixi.isScrollBottom, {
            DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.005) {
                if self.models.count > 0 {
                    tableView.scrollToRow(at: IndexPath(row: self.models.count - 1, section: 0), at: .bottom, animated: false)
                }
            }
        })
        return models.count
    }
 
    func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
        let message = models[indexPath.row]
        var height: CGFloat = 0
        height = tableView.fd_heightForCell(withIdentifier: message.type.identifier, cacheByKey: "\(message.timestamp)" as NSCopying, configuration: { (cell) in
            (cell as! ChatViewCell).message = message
        })
        return ceil(height)
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let message = models[indexPath.row]
        let cell: ChatViewCell = tableView.dequeueReusableCell(withIdentifier: message.type.identifier) as! ChatViewCell
        cell.selectionStyle = .none
        cell.message = message
        return cell
    }
}

二、ChatViewController.swift

1、创建随机消息添加到屏幕上

创建一个定时器,每0.1秒添加一个Message至缓存池,缓存池会根据设置的时间定时将Message数组添加到ChatTableView上。

2、键盘弹出的处理

一般聊天界面,会有聊天框和聊天内容,关于键盘的显示和消失时的处理参考聊天界面键盘隐藏时的一个动画小问题的方式处理,当键盘弹出时,不改变ChatTableView的大小,将其向上平移,就避免了ChatTableView的那个奇怪的动画。

3、ChatTableView添加Message的刷新加载

关于Reloadable.refresh(_ models: [(Self.Model, MAExtension.RefreshMode)])下篇文章讲解。

import UIKit

class ChatViewController: UIViewController {

    @IBOutlet weak var tableView: ChatTableView!
    @IBOutlet weak var toolView: UIView!
    @IBOutlet weak var toolViewBottomLayout: NSLayoutConstraint!
    @IBOutlet weak var tableViewTopLayout: NSLayoutConstraint!
        
    var messagePool: MessagePool<(Message, RefreshMode)>!

    // 是否添加消息
    var isAddMessage = true
    var timer: Timer?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.tableView.delegate = self

        startObserve()
    
        // 定时添加消息
        timer = Timer.timer(interval: 0.1, repeats: true, block: {[weak self] (timer) in
            if let weakSelf = self {
                if weakSelf.isAddMessage == true {
                    weakSelf.add(messages: [Message.randomMessage()])
                }
            }
        })
        // 设置缓存池
        messagePool = MessagePool.init(interval: 0.5, maxPop: 50) {[unowned self] (messages) in
            if messages.count > 0 {
                self.tableView.refresh(messages)
            }
        }
    }
    // 添加消息
    func add(messages: [Message]){
        if messages.count == 0 { return }
        messagePool.push(messages.map{($0, .insert(.bottom))})
    }
    
    @IBAction func refresh(_ sender: UIBarButtonItem) {
        self.isAddMessage = !self.isAddMessage
        sender.title = self.isAddMessage ? "auto" : "stop"
    }
    
    @IBAction func addMessages(_ sender: UIBarButtonItem) {
        add(messages: [Message.randomMessage()])
    }
    
    @IBAction func remove(_ sender: UIBarButtonItem) {
        Message.sortIndex = -1
        self.tableView.models = []
        self.tableView.reloadData()
    }
    
    deinit {
        self.timer?.invalidate()
        self.timer = nil
        cleanCache()
        NotificationCenter.default.removeObserver(self)
    }
}
// MARK: - 键盘的监听
extension ChatViewController {
    
    func startObserve(){
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notify:)), name: Notification.Name.UIKeyboardWillShow, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notify:)), name: Notification.Name.UIKeyboardWillHide, object: nil)
    }
    
    // 键盘将要出现
    @objc func keyboardWillShow(notify: NSNotification){
        let top = self.tableView.frame.origin.y
        UIView.animate(withDuration: notify.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double, delay: 0, options: UIViewAnimationOptions.init(rawValue: notify.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt), animations: {
            let height = (notify.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue.size.height
            self.toolViewBottomLayout.constant = height
            self.tableViewTopLayout.constant = -height
            self.view.layoutIfNeeded()
            // 将界面的上消息较少时,需要特殊处理调整contentInset
            if(self.tableView.contentSize.height - self.tableView.bounds.size.height < 0){
                self.tableView.contentInset = UIEdgeInsetsMake(height-top, 0, 0, 0);
            }else{
                self.tableView.scrollBottom()
            }
        }, completion: nil)
    }
    // 键盘将要消失
    @objc func keyboardWillHide(notify: NSNotification){
        UIView.animate(withDuration: notify.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double, delay: 0, options: UIViewAnimationOptions.init(rawValue: notify.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt), animations: {
            self.toolViewBottomLayout.constant = 0
            self.tableViewTopLayout.constant = 0
            self.view.layoutIfNeeded()
            self.tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
        }, completion: nil)
    }
}

extension ChatViewController: UITableViewDelegate {
    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        self.toolView.endEditing(true)
    }
}

上一篇:聊天功能(三)--创建TextCell、ImageCell等
下一篇:聊天功能(五)--ChatTableView的刷新能力Reloadable

Demo地址:MAChatTableViewDemo

相关文章

网友评论

    本文标题:聊天功能(四)--创建ChatViewController

    本文链接:https://www.haomeiwen.com/subject/trawsftx.html