我正在创建一个应用程序,在那里我必须在主屏幕上显示Spot,但用户必须解锁该Spot才能观看它,它有标签,启动计数器60秒.这是我的定时器功能.

timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(updateCounter), userInfo: nil, repeats: true)

 @objc func updateCounter() {
 if counter > 0 {

            let time = Int(counter/60)
            let dec = Int(counter.truncatingRemainder(dividingBy: 60))
            spotTiming = String(time) + ":" + String(dec)
            }
            counter -= 1
}

And this is how it will be shown on screenenter image description here

在任何地点进行胶带后,计数器将开始计时.但我的问题是如何在两个以上相同Counter Function的标签上启动计数器.由于用户可以点击两个不同的位置,相差10秒,而我只有一个计数器功能,所以我如何启动两个不同的计数器.有没有其他方法可以推荐给我,我将不胜感激!谢谢. 根据用户的不同,PS个广告位可以是多个.

推荐答案

假设你想让每个"点"在点击时开始"从60开始倒计时",这里有一个简单的例子……

我们将创建一个带有标签和圆形边框的UIView子类.

它还将有一个"startTime"属性:

private var startTime: Date?

当我们点击视图时,我们将开始时间设置为"Now":

startTime = Date()

我们将有一个函数来更新倒计时:

public func timerFired(_ now: Date) {
    if let st = startTime {
        let elapsedSeconds = Int(floor(now.timeIntervalSinceReferenceDate - st.timeIntervalSinceReferenceDate))
        label.text = "\(60 - elapsedSeconds)"
        // if we've reached 60-seconds, set startTime to nil
        //  so we don't keep going to -1, -2, -3 etc
        if elapsedSeconds == 60 {
            self.startTime = nil
        }
    }
}

在我们的控制器中,我们将有一个每隔0.3秒触发的single次重复计时器.如果我们每秒只emits 一次,我们就可以"跳过"数字:

    // use less-than 1-second for the timeInterval... otherwise, we *could* end up with
    //  skipped seconds. That is, we might see "60  59  58  56  55  53 etc"
    Timer.scheduledTimer(timeInterval: 0.3, target: self, selector: #selector(timerFunc), userInfo: nil, repeats: true)

每次触发计时器函数时,我们都会通过呼叫.timerFired()来告诉每个"Spot"视图,然后"Spot"视图会将自己的startTime与新时间进行比较,并更新其标签.

因此,下面是我们的定制SpotView级:

class SpotView: UIView {
    
    private var startTime: Date?
    
    private let label = UILabel()

    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    private func commonInit() {
        label.numberOfLines = 0
        label.text = "Unlock\nto See"
        label.textAlignment = .center
        label.translatesAutoresizingMaskIntoConstraints = false
        addSubview(label)
        NSLayoutConstraint.activate([
            label.centerXAnchor.constraint(equalTo: centerXAnchor),
            label.centerYAnchor.constraint(equalTo: centerYAnchor),
        ])
        layer.borderColor = UIColor.red.cgColor
        layer.borderWidth = 1
        
        let g = UITapGestureRecognizer(target: self, action: #selector(gotTap(_:)))
        addGestureRecognizer(g)
    }
    override func layoutSubviews() {
        super.layoutSubviews()
        let m: CGFloat = min(bounds.width, bounds.height)
        layer.cornerRadius = m * 0.5
    }
    @objc func gotTap(_ g: UITapGestureRecognizer) {
        // set the startTime property to "now"
        startTime = Date()
        label.text = "60"
    }
    public func timerFired(_ now: Date) {
        if let st = startTime {
            let elapsedSeconds = Int(floor(now.timeIntervalSinceReferenceDate - st.timeIntervalSinceReferenceDate))
            label.text = "\(60 - elapsedSeconds)"
            // if we've reached 60-seconds, set startTime to nil
            //  so we don't keep going to -1, -2, -3 etc
            if elapsedSeconds == 60 {
                self.startTime = nil
            }
        }
    }
}

和一个样本控制器:

class FourSpotsVC: UIViewController {
    
    var theSpots: [SpotView] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let w: CGFloat = 100.0
        let h: CGFloat = 100.0
        
        var x: CGFloat = 40.0
        var y: CGFloat = 100.0
        
        // let's add 4 "Spot" views
        for i in 0..<4 {
            x = i % 2 == 0 ? 40.0 : 160.0
            let v = SpotView()
            v.frame = CGRect(x: x, y: y, width: w, height: h)
            view.addSubview(v)
            theSpots.append(v)
            y += h + 20.0
        }
    }
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        // use less-than 1-second for the timeInterval... otherwise, we *could* end up with
        //  skipped seconds. That is, we might see "60  59  58  56  55  53 etc"
        Timer.scheduledTimer(timeInterval: 0.3, target: self, selector: #selector(timerFunc), userInfo: nil, repeats: true)
    }
    @objc func timerFunc() {
        let n = Date()
        theSpots.forEach { v in
            v.timerFired(n)
        }
    }
}

run 时是这样的(我点击了第一个点,然后等待了大约10秒,然后点击第二个点):

enter image description here

Ios相关问答推荐

SWIFT根据地球坐标修改 node 旋转

删除领域中的cartItem时出现问题

如何将模糊输入/模糊输出添加到SwiftUI中的非对称过渡?

objc[25442]:Swift类的扩展和类别不允许有+load方法

许多文本字段的性能问题

如何使用 pushViewController 从 UIHostingController 的 SwiftUI 视图中推送 ViewController?

叠加视图不在堆栈中维护自身 - SwiftUI

iOS SwiftUI - 从以前的 struct 调用函数

使用 CIImage 支持的 UIImage 设置 UIImageView 时发生罕见的崩溃

检测 iPhone 应用程序中是否存在摄像头?

如何 comments .plist 文件中的行?

UICollectionView - 动态单元格高度?

如何判断是否为 64 位构建了静态库?

每个版本的 iOS 都附带什么版本的移动 Safari?

使用 Chrome DevTools 调试 iOS 6+7 Mobile Safari

iPhone:什么是 WWDR 中级证书?

如何防止 iOS 设备上的显示屏变暗和关闭?

iOS应用程序每隔一次启动就会崩溃,找不到错误

UICollectionView:必须用非零布局参数初始化

NSURL 到带有 XCTest 的测试包中的文件路径