美文网首页IOS
iOS 在TableViewCell上显示倒计时功能

iOS 在TableViewCell上显示倒计时功能

作者: c6e16b2e3a16 | 来源:发表于2017-03-30 16:08 被阅读677次

    倒计时一般会想到用NSTimer(Timer)来计时,对于不是要非常精确地计时来说,已经够用了.这里也是用NSTimer(Timer)来计时的.在tableview上显示多个倒计时需要考虑用一个计时器还是每个cell都设置一个计时器.这里完成100毫秒(0.1秒)倒计时功能.

    准备工作:Xcode8.2,swift3.0

    1.使用一个计时器

    先创建一个数据模型类,用于保存网络下载的数据.
    如果需要倒计时,下载下来的数据肯定有一个时间结束的参数endTime

    class TimeModel: NSObject {
        var endTime:String? //结束时间,这是从网咯下载的数据
        var leftTime:String? //剩余时间,根据endTime做相关处理,显示在cell上的倒计时
        var remain:TimeInterval = 0.0//剩余时间
    }
    

    这里使用了storyboard创建控制器

    @IBOutlet weak var tableView: UITableView!
    var timer:Timer?
    var dataArray = Array<TimeModel>()
    

    这里模拟网络下载创建一些数据

    //模拟数据
        func createTime()  {
            //模拟网络请求数据
            for _ in 0..<30 {
                let M = arc4random()%12+1//月
                var d = arc4random()%31+1//日
                let h = arc4random()%24//小时
                let m = arc4random()%60//分钟
                let s = arc4random()%60//秒
            //大小月纠正,这里是模拟数据,无需很严格
                if M == 2 {
                    d = d >= 28 ? 28 : d
                } else if M == 4 || M == 6 || M == 9 || M == 11 {
                    d = d >= 31 ? 30 : d
                }
                let model:TimeModel = TimeModel()
                model.endTime = String(format: "2017-%02d-%02d %02d:%02d:%02d", M, d, h, m, s)
                dataArray.append(model)
            }
            //对于下载的数据做初步处理
            for model in dataArray {
                let date = dateFormatter.date(from: model.endTime!)!
                let leftTime = date.timeIntervalSinceNow
                model.remain = leftTime > 0 ? leftTime : 0
                //秒转时间
                let ss = Int(model.remain)
                let d = ss / (24*3600)
                let h = ss % (24*3600) / 3600
                let m = ss % 3600 / 60
                let s = ss % 60
                let u = (Int)(model.remain - Double(ss)) * 10
                model.leftTime = String(format: "%03d天%02d:%02d:%02d.%d", d, h, m, s, u)
            }
            tableView.reloadData()
            startTimer()
        }
    
        //开启计时器
        func startTimer() {
            if (timer != nil) {
                timer!.invalidate()
                timer = nil
            }
            timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(refreshTime), userInfo: nil, repeats: true)
        //默认加入到.defaultRunLoopMode,tableview滑动时会阻塞线程.
            RunLoop.current.add(timer!, forMode: .commonModes)
        }
    
        //刷新时间界面
        func refreshTime() {
            var status = true //是否结束倒计时,true结束,false进行中
            for i in 0..<dataArray.count {
                let model = dataArray[i]
                if model.remain > 0 {
                    status = false
                    if model.remain > 0.1 {
                        model.remain -= 0.1
                        //秒转时间
                        let ss = Int(model.remain)
                        let d = ss / (24*3600)
                        let h = ss % (24*3600) / 3600
                        let m = ss % 3600 / 60
                        let s = ss % 60
                        let u = (Int)((model.remain - Double(ss)) * 10)
                        model.leftTime = String(format: "%03d天%02d:%02d:%02d.%d", d, h, m, s, u)
                    } else {
                        model.remain = 0
                        model.leftTime = "000天00:00:00.0"
                    }
                    let cell = tableView.cellForRow(at: IndexPath(row: i, section: 0))
                    if cell != nil {
                        cell?.textLabel?.text = model.leftTime
                    }
                }
            }
            if status {
                timer?.invalidate()
                timer = nil
            }
        }
        ```
    
    //DateFormatter是比较消耗资源的,这里使用懒加载全局变量的形式创建
    lazy var dateFormatter: DateFormatter = {
        var dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        return dateFormatter
    }()
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cellId = "cellId"
        var cell = tableView.dequeueReusableCell(withIdentifier: cellId)
        if cell == nil {
            cell = UITableViewCell(style: .default, reuseIdentifier: cellId)
        }
        let model = dataArray[indexPath.row]
        cell?.textLabel?.text = model.leftTime
        return cell!
    }
    
    #####优化:
    对于数据比较少且不用非常非常精确的计时功能,以上已经足够了.这里有几个可以优化的地方
    ######①筛选数据
    将需要倒计时的数据保存在字典中,只对这些数据计时.这样对于数据量大的操作科技减少很多计算量.
    

    //保存需要计时的数据
    var dataDict = IndexPath:TimeModel

    //数据处理时筛选出需要计时的数据
    for i in 0..<dataArray.count {
    let model = dataArray[i]
    let date = dateFormatter.date(from: model.endTime!)!
    let leftTime = date.timeIntervalSinceNow
    //如果结束时间比现在时间早,剩余时间设为0
    model.remain = leftTime > 0 ? leftTime : 0
    if model.remain > 0 {
    //秒转时间
    let ss = Int(model.remain)
    let d = ss / (243600)
    let h = ss % (24
    3600) / 3600
    let m = ss % 3600 / 60
    let s = ss % 60
    let u = (Int)(model.remain - Double(ss)) * 10
    model.leftTime = String(format: "%03d天%02d:%02d:%02d.%d", d, h, m, s, u)
    let indexPath = IndexPath(row: i, section: 0)
    dataDict[indexPath] = model
    } else {
    model.leftTime = "000天00:00:00.0"
    }

    func refreshTime() {
        var status = true //是否结束倒计时,true结束,false进行中
        for (indexPath, model) in dataDict {
            if model.remain > 0 {
                status = false
                if model.remain > 0.1 {
                    model.remain -= 0.1
                    //秒转时间
                    let ss = Int(model.remain)
                    let d = ss / (24*3600)
                    let h = ss % (24*3600) / 3600
                    let m = ss % 3600 / 60
                    let s = ss % 60
                    let u = (Int)((model.remain - Double(ss)) * 10)
                    model.leftTime = String(format: "%03d天%02d:%02d:%02d.%d", d, h, m, s, u)
                } else {
                    model.remain = 0
                    model.leftTime = "000天00:00:00.0"
                    dataDict.removeValue(forKey: indexPath)//如果计时结束,移除数据
                }
                let cell = tableView.cellForRow(at: indexPath)
                if cell != nil {
                    cell?.textLabel?.text = model.leftTime
                }
            }
        }
        if status {
            timer?.invalidate()
            timer = nil
        }
    }
    
    也可以
    

    //保存需要计时的数据的IndexPath,获取dataArray中的model进行计算
    var indexArray = Array<IndexPath>()

    相关文章

      网友评论

        本文标题:iOS 在TableViewCell上显示倒计时功能

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