在UITableView中延迟插入行



我有一个类似于聊天应用程序的UI,需要以气泡的形式显示消息(UILabels)。我已将UITableView用于包含标签的自定义单元格。

示例:假设我最初有3条消息。

Hi
How are you?
What can I do for you?

我希望这3个细胞一个接一个地出现,并有一些延迟,以便获得聊天般的体验。我试过dispatch_after,在区块内我有

[tableView insertRowsAtIndexPath: withAnimation:]

但是这在没有任何延迟的情况下将3行全部插入在一起。有人能帮忙吗?

您的需求类似于在气泡中显示消息的聊天应用程序。

已有演示,您可以轻松下载和配置。从零开始创建后无需花费时间。

https://github.com/tkirby/BubbleThingie

https://mobiforge.com/design-development/sms-bubble-ui-iphone-apps

https://github.com/RobinChao/ChatMessageTableViewController

这应该可以工作,但您必须添加更新和主队列。

[tableView beginUpdates]
[tableView insertRowsAtIndexPath: withAnimation:]
[tableView endUpdates]

要在主线程上执行操作,请使用

 dispatch_async(dispatch_get_main_queue(), {() -> Void in
 })

您还可以一次插入所有这些行,并将alpha=0设置为带文本的UILabels。然后,可以使用几个连续的[UIWiew animateWithDuration]将alpha平滑设置为1,标签就会出现。

   import Foundation
   import UIKit
   import QuartzCore
   import AVFoundation
 class ChatPracticeVC: UIViewController ,UITableViewDelegate, UITableViewDataSource {
//MARK: Properties
var tableView: UITableView!
var items = [Messages]()
var names = ["item1", "item2", "item3, "item4"] // ... you can add as many names as you want
var directions = ["right", "left", "right", "right"]
let barHeight: CGFloat = 50
var timer: DispatchSourceTimer!
var continueButt:UIButton!
var showContinueButt = true
override func viewDidLoad() {
    super.viewDidLoad()
    tableView = UITableView(frame:CGRect.zero)
    tableView.dataSource = self
    tableView.delegate = self
    self.view.addSubview(tableView)
    self.tableView.separatorStyle = .none
    self.customization()
}
override func viewWillAppear(_ animated: Bool) {
    tableView.register(UINib(nibName: "ReceiverCell", bundle: nil), forCellReuseIdentifier: "receiverCell")
    tableView.register(UINib(nibName: "SenderCell", bundle: nil), forCellReuseIdentifier: "senderCell")
}
override func viewWillLayoutSubviews() {
    let height: CGFloat = 66
    tableView.frame = CGRect(x: 0, y: (self.navigationController?.navigationBar.frame.height)!, width: view.bounds.size.width, height: view.bounds.size.height - height - 1.0)
}
override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(true)
    self.insertItem(index: 0)
    DispatchQueue.main.asyncAfter(deadline: .now() + 4) { // change 2 to desired number of seconds
        self.insertTimer(i: 1)
    }
}
func insertItem(index:Int){
    self.items.append(Messages(message: (self.names[index]), position: (self.directions[index])))
    CATransaction.begin()
    self.tableView.beginUpdates()
    let lines = self.names[index].components(separatedBy: .newlines)
    let indexPath:IndexPath = IndexPath(row:(self.items.count - 1), section:0)
    CATransaction.setCompletionBlock {
        //you can insert animation code here on loading of cell
    }
    CATransaction.commit()
    self.tableView.insertRows(at: [indexPath], with: .bottom)
    self.tableView.endUpdates()
    self.tableView.scrollToRow(at: indexPath, at: .bottom, animated: false)
}
func delay(_ delay:Double, closure:@escaping ()->()) {
    DispatchQueue.main.asyncAfter(
        deadline: DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: closure)
}
func insertTimer(i :Int){
    var index = i
    timer = DispatchSource.makeTimerSource(queue: .main)
    timer.schedule(deadline: .now(), repeating: .seconds(4))
    timer.setEventHandler { [weak self] in
        self?.insertItem(index: index)
        index = index.advanced(by: 1)
        if index == self?.names.endIndex {
            if(self?.names.count == 13){
                self?.continueButt.setTitle("Finish", for: .normal)
            }
            self?.timer.cancel()
            self?.showAndHideBottomBar()
        }
    }
    timer.resume()
}
//MARK: Methods
func customization() {
    self.tableView.estimatedRowHeight = self.barHeight
    self.tableView.rowHeight = UITableViewAutomaticDimension
    self.tableView.contentInset.bottom = self.barHeight
    self.tableView.scrollIndicatorInsets.bottom = self.barHeight
    continueButt = UIButton(type: .custom)
    self.view.addSubview(continueButt)
    continueButt = UIButton(frame: CGRect(x:0, y:0, width:self.view.bounds.width, height:50))
    continueButt.backgroundColor = UIColor(red: 0, green: 185/255, blue: 210/255, alpha: 1)
    continueButt.setTitle("CONTINUE", for: .normal)
    continueButt.frame.origin = CGPoint(x:0, y:self.view.frame.size.height - continueButt.frame.size.height)
    continueButt.addTarget(self, action: #selector(self.continueButtClicked), for: .touchUpInside)
    self.view.addSubview(continueButt)
    continueButt.layer.zPosition = .greatestFiniteMagnitude
    showAndHideBottomBar()
}
//Hides current viewcontroller
@objc func dismissSelf() {
    if let navController = self.navigationController {
        navController.popToRootViewController(animated: true)
    }
}
@objc func continueButtClicked(_ sender: UIButton) {
    view.endEditing(true)
    showAndHideBottomBar()
    if(sender.titleLabel?.text == "Finish"){
        self.navigationController?.pushViewController(FinishVC(), animated: true)
    }
    if(names.count == 4){
        let i = names.count
        names.append("item5")
        names.append("item6")
        names.append("item7")
        names.append("item8")
        directions.append("left")
        directions.append("right")
        directions.append("left")
        directions.append("right")
        self.insertTimer(i: i )
    }
    else if(names.count == 8){
        let i = names.count
        names.append("item9")
        names.append("item10")
        directions.append("right")
        directions.append("left")
        self.insertTimer(i: i )
    }
   else if(names.count == 10){
        let i = names.count
        names.append("item11")
        names.append("item12")
        names.append("item13")
        directions.append("right")
        directions.append("right")
        directions.append("left")
        self.insertTimer(i: i )
    }
}
//MARK: Delegates
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let temp:UITableViewCell = UITableViewCell()
    switch self.items[indexPath.row].position {
    case "right":
        let cell = tableView.dequeueReusableCell(withIdentifier: "receiverCell", for: indexPath) as! ReceiverCell
        cell.clearCellData()
        cell.profilePic.image = UIImage(named:"user.png")
        cell.message.text = self.items[indexPath.row].message
        return cell
    case "left":
        let cell = tableView.dequeueReusableCell(withIdentifier: "senderCell", for: indexPath) as! SenderCell
        cell.clearCellData()
        cell.profilePic.image = UIImage(named:"user.png")
        cell.message.text = self.items[indexPath.row].message
        return cell
    default:
        return temp
    }
}
func showAndHideBottomBar() {
    if showContinueButt == false {
        self.continueButt.alpha = 0.0
        self.continueButt.isHidden = false
        self.showContinueButt = true
        UIView.animate(withDuration: 0.6, delay: 0, options: .curveEaseInOut, animations: {
            self.continueButt.alpha = 1.0
        }) { (isCompleted) in
        }
    } else{
        UIView.animate(withDuration: 0.6, delay: 0, options: .curveEaseInOut, animations: {
            self.continueButt.alpha = 0.0
        }) { (isCompleted) in
            self.continueButt.isHidden = true
            self.showContinueButt = false
        }
    }
}
}

在这里,我使用了定时器在数组中插入项目,然后将其插入表视图(检查方法insertItem和insertTimer),从而产生加载延迟效果这个例子应该模仿你的聊天需求

最新更新