IOS

iOS 在TableViewCell上显示倒计时功能

2017-03-30  本文已影响677人  c6e16b2e3a16

倒计时一般会想到用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>()

上一篇 下一篇

猜你喜欢

热点阅读