簡體   English   中英

如何暫停 SwiftUI 中使用的定時器?

[英]How can I pause a Timer being used in SwiftUI?

我有這個 function 改變了 map 的中心位置,這導致 map 在所有位置上進行動畫處理。 緯度和經度正在遞增和遞減,並使用計時器重復。 但是我目前正在嘗試暫停計時器。 我嘗試了多種方法,似乎無法讓計時器暫停幾秒鍾並恢復。 唯一有效的是使用睡眠,但這會導致整個 UI 暫停。 這個“移動”function 正在更新@State CLLocationCoordinate 的經緯度。 此方法稱為 in.onAppear()。

timer.fire() 不起作用

我也嘗試過這樣的事情:

        timer.invalidate()
         DispatchQueue.main.asyncAfter(deadline: .now() + 5.00) {
          
            timer.fire()
        }

上面的代碼不起作用

    func moveRegion() {
        
            var currentLatitude = region.center.latitude
            var currentLongitude = region.center.longitude
        
            let increment = 0.25
            var southAmerica = false
            var europe = false
            var australia = false
            var america = true
        
            Timer.scheduledTimer(withTimeInterval: (1.0/30.0), repeats: true) { (timer) in
                //AMERICA CORD 37.0000, -95.000
                //MOVING TO SOUTH AMERICA
                //SOUTH AMERICA CORD -33.000, -70.000
                if (america == true && southAmerica == false && europe == false && australia == false){
                    if (currentLatitude <= -33.000 && currentLatitude >= 37.0000 || currentLongitude <= -70.0000 && currentLongitude >= -95.0000 || currentLongitude >= -101.69999999998991) {
                        currentLatitude -= increment
                        currentLatitude -= increment
                        currentLatitude -= increment
                        if currentLongitude < -70.00 {
                            currentLongitude += increment
                        }
                    }
                    if (currentLatitude == -38.15000000000002 || currentLatitude <= -38.150000000000006  && currentLongitude <=  -69.95000000000142){
                       // sleep(5), works but pauses whole UI
                        timer.invalidate()
                        Timer.scheduledTimer(withTimeInterval: 5.0, repeats: false) { pauseTimer in
                            timer.fire()
                            print(timer.isValid)
                        }
                      
                        southAmerica = true
                        australia = false
                        america = false
                        europe = false
                    }
                }
                //MOVING TO EUROPE
                //Europe CORD 48.000, 15.000
                //if (currentLongitude > -74.00 && currentLongitude < -4.00)
                    if (southAmerica == true && australia == false && america == false && europe == false ){
                        if (currentLatitude > -39.000 && currentLatitude <  55.000 || currentLongitude > -70.00 && currentLongitude < 16.000) {
                            currentLongitude += increment
                            currentLongitude += increment
                            currentLatitude += increment
                            currentLatitude += increment
                        }
                        if (currentLatitude >= 48.04999999999936 || currentLatitude == 48.04999999999937 && currentLongitude <= 16.249999999996835){
                            
                            sleep(5)
                            
                            europe = true
                            southAmerica = false
                            australia = false
                            america = false
                        }
                    }
                    //MOVING TO AUSTRALIA
                    //AUSTRALIA CORD -36.000, 133.000
                    if (europe == true && southAmerica == false && australia == false && america == false){
                        if (currentLongitude > 9.00 && currentLongitude < 133.000) {
                            currentLongitude += increment
                            currentLongitude += increment
                            currentLongitude += increment
                        }
                        if (currentLatitude >= -38.000 && currentLatitude <= 49.0000){
                            currentLatitude -= increment
                            currentLatitude -= increment
                        }
                    if (currentLatitude <= -37.05000000000008  && currentLongitude >= 132.04999999999274){
                        sleep(5)
                        australia = true
                        southAmerica = false
                        europe = false
                        america = false
                    }
                }
                    //MOVING TO AMERIA
                    if (australia == true && southAmerica == false && america == false && europe == false){
                        if (currentLongitude < 179.55){
                            currentLongitude += increment
                            currentLongitude += increment
                            if (currentLongitude > 179.500){
                                currentLongitude = -179.000
                              }
                        }
                        if (currentLongitude > -95.100) {
                            currentLongitude += increment
                            currentLongitude += increment
                        }
                        if (currentLatitude >= -39.000 && currentLatitude <= 37.0000){
                            currentLatitude += increment
                            currentLatitude += increment
                        }
                    if (currentLatitude >= 37.04999999999998 && currentLongitude >= -95.100){
                        australia = false
                        southAmerica = false
                        europe = false
                        america = true
                        currentLatitude = 37.0000
                        currentLongitude = -95.000
                        sleep(5)
                    }
                }
                region.center.longitude = currentLongitude
                region.center.latitude = currentLatitude
                centerLocation.latitude = currentLatitude
                centerLocation.longitude = currentLongitude
               }
        
    }

然后在視圖中

            var body: some View {

        SwiftUIMapView(centerLocation: $centerLocation)
            .onAppear {
                DispatchQueue.main.async {
                  moveRegion()
                }
                
            }
    }

下面是完整的代碼:

import SwiftUI
import MapKit

struct MapView: View {

    var timer = Timer()
    //Start Location of the Map
    @State var region = MKCoordinateRegion(
        center: CLLocationCoordinate2D(latitude: 37.0000, longitude: -95.000),
        span: MKCoordinateSpan(latitudeDelta: 40, longitudeDelta: 40)
    )
    
    @State var centerLocation = CLLocationCoordinate2D()
   

    func moveRegion() {
        
            var currentLatitude = region.center.latitude
            var currentLongitude = region.center.longitude
        
            let increment = 0.25
            var southAmerica = false
            var europe = false
            var australia = false
            var america = true
        
            Timer.scheduledTimer(withTimeInterval: (1.0/30.0), repeats: true) { (timer) in
                //AMERICA CORD 37.0000, -95.000
                //MOVING TO SOUTH AMERICA
                //SOUTH AMERICA CORD -33.000, -70.000
                if (america == true && southAmerica == false && europe == false && australia == false){
                    if (currentLatitude <= -33.000 && currentLatitude >= 37.0000 || currentLongitude <= -70.0000 && currentLongitude >= -95.0000 || currentLongitude >= -101.69999999998991) {
                        currentLatitude -= increment
                        currentLatitude -= increment
                        currentLatitude -= increment
                        if currentLongitude < -70.00 {
                            currentLongitude += increment
                        }
                    }
                    if (currentLatitude == -38.15000000000002 || currentLatitude <= -38.150000000000006  && currentLongitude <=  -69.95000000000142){
                       // sleep(5), works but pauses whole UI
                        timer.invalidate()
                        Timer.scheduledTimer(withTimeInterval: 5.0, repeats: false) { pauseTimer in
                            timer.fire()
                            print(timer.isValid)
                        }
                      
                        southAmerica = true
                        australia = false
                        america = false
                        europe = false
                    }
                }
                //MOVING TO EUROPE
                //Europe CORD 48.000, 15.000
                //if (currentLongitude > -74.00 && currentLongitude < -4.00)
                    if (southAmerica == true && australia == false && america == false && europe == false ){
                        if (currentLatitude > -39.000 && currentLatitude <  55.000 || currentLongitude > -70.00 && currentLongitude < 16.000) {
                            currentLongitude += increment
                            currentLongitude += increment
                            currentLatitude += increment
                            currentLatitude += increment
                        }
                        if (currentLatitude >= 48.04999999999936 || currentLatitude == 48.04999999999937 && currentLongitude <= 16.249999999996835){
                            
                            sleep(5)
                            
                            europe = true
                            southAmerica = false
                            australia = false
                            america = false
                        }
                    }
                    //MOVING TO AUSTRALIA
                    //AUSTRALIA CORD -36.000, 133.000
                    if (europe == true && southAmerica == false && australia == false && america == false){
                        if (currentLongitude > 9.00 && currentLongitude < 133.000) {
                            currentLongitude += increment
                            currentLongitude += increment
                            currentLongitude += increment
                        }
                        if (currentLatitude >= -38.000 && currentLatitude <= 49.0000){
                            currentLatitude -= increment
                            currentLatitude -= increment
                        }
                    if (currentLatitude <= -37.05000000000008  && currentLongitude >= 132.04999999999274){
                        sleep(5)
                        australia = true
                        southAmerica = false
                        europe = false
                        america = false
                    }
                }
                    //MOVING TO AMERIA
                    if (australia == true && southAmerica == false && america == false && europe == false){
                        if (currentLongitude < 179.55){
                            currentLongitude += increment
                            currentLongitude += increment
                            if (currentLongitude > 179.500){
                                currentLongitude = -179.000
                              }
                        }
                        if (currentLongitude > -95.100) {
                            currentLongitude += increment
                            currentLongitude += increment
                        }
                        if (currentLatitude >= -39.000 && currentLatitude <= 37.0000){
                            currentLatitude += increment
                            currentLatitude += increment
                        }
                    if (currentLatitude >= 37.04999999999998 && currentLongitude >= -95.100){
                        australia = false
                        southAmerica = false
                        europe = false
                        america = true
                        currentLatitude = 37.0000
                        currentLongitude = -95.000
                        sleep(5)
                    }
                }
                region.center.longitude = currentLongitude
                region.center.latitude = currentLatitude
                centerLocation.latitude = currentLatitude
                centerLocation.longitude = currentLongitude
               }
        
    }

    var body: some View {

        SwiftUIMapView(centerLocation: $centerLocation)
            .onAppear {
                DispatchQueue.main.async {
                  moveRegion()
                }
                
            }
    }
}

非常感謝您的任何幫助,謝謝!

為此使用Timer並嘗試使invalidate 、 re-fire 等變得困難(或者實際上是不可能的—— Timer一旦失效就無法重新觸發)。 但是,這似乎是一個很好的機會,可以通過 Combine 在發布者中使用Timer ,然后給它一些時間間隔來等待——發布者仍然會觸發事件,它只是在下一個等待時間間隔之前不對它們做任何事情被擊中:


struct ContentView : View {
    var body: some View {
        MapView()
    }
}

class LocationManager : ObservableObject {
    @Published var centerLocation = CLLocationCoordinate2D()
    @Published var region : MKCoordinateRegion
    
    private var currentLatitude : CLLocationDegrees
    private var currentLongitude : CLLocationDegrees
    
    init() {
        let region = MKCoordinateRegion(
            center: CLLocationCoordinate2D(latitude: 37.0000, longitude: -95.000),
            span: MKCoordinateSpan(latitudeDelta: 40, longitudeDelta: 40)
        )
        currentLatitude = region.center.latitude
        currentLongitude = region.center.longitude
        self.region = region
    }
    
    private var cancellable : AnyCancellable?
    
    private var waitUntil : Date?
    private var currentFireDate : Date = Date()
    
    func start() {
        cancellable = Timer.publish(every: (1.0/30.0), on: .main, in: .default)
            .autoconnect()
            .sink { val in
                if let waitUntil = self.waitUntil {
                    if val < waitUntil {
                        return
                    } else {
                        self.waitUntil = nil
                    }
                }
                self.currentFireDate = val
                self.moveRegion()
            }
    }
    
    let increment = 0.25
    var southAmerica = false
    var europe = false
    var australia = false
    var america = true
    
    func moveRegion() {
        //AMERICA CORD 37.0000, -95.000
        //MOVING TO SOUTH AMERICA
        //SOUTH AMERICA CORD -33.000, -70.000
        if (america == true && southAmerica == false && europe == false && australia == false){
            if (currentLatitude <= -33.000 && currentLatitude >= 37.0000 || currentLongitude <= -70.0000 && currentLongitude >= -95.0000 || currentLongitude >= -101.69999999998991) {
                currentLatitude -= increment
                currentLatitude -= increment
                currentLatitude -= increment
                if currentLongitude < -70.00 {
                    currentLongitude += increment
                }
            }
            if (currentLatitude == -38.15000000000002 || currentLatitude <= -38.150000000000006  && currentLongitude <=  -69.95000000000142){
                waitUntil = currentFireDate.addingTimeInterval(5.0)
                
                southAmerica = true
                australia = false
                america = false
                europe = false
            }
        }
        //MOVING TO EUROPE
        //Europe CORD 48.000, 15.000
        //if (currentLongitude > -74.00 && currentLongitude < -4.00)
        if (southAmerica == true && australia == false && america == false && europe == false ){
            if (currentLatitude > -39.000 && currentLatitude <  55.000 || currentLongitude > -70.00 && currentLongitude < 16.000) {
                currentLongitude += increment
                currentLongitude += increment
                currentLatitude += increment
                currentLatitude += increment
            }
            if (currentLatitude >= 48.04999999999936 || currentLatitude == 48.04999999999937 && currentLongitude <= 16.249999999996835){
                
                waitUntil = currentFireDate.addingTimeInterval(5.0)
                
                europe = true
                southAmerica = false
                australia = false
                america = false
            }
        }
        //MOVING TO AUSTRALIA
        //AUSTRALIA CORD -36.000, 133.000
        if (europe == true && southAmerica == false && australia == false && america == false){
            if (currentLongitude > 9.00 && currentLongitude < 133.000) {
                currentLongitude += increment
                currentLongitude += increment
                currentLongitude += increment
            }
            if (currentLatitude >= -38.000 && currentLatitude <= 49.0000){
                currentLatitude -= increment
                currentLatitude -= increment
            }
            if (currentLatitude <= -37.05000000000008  && currentLongitude >= 132.04999999999274){
                waitUntil = currentFireDate.addingTimeInterval(5.0)
                australia = true
                southAmerica = false
                europe = false
                america = false
            }
        }
        //MOVING TO AMERIA
        if (australia == true && southAmerica == false && america == false && europe == false){
            if (currentLongitude < 179.55){
                currentLongitude += increment
                currentLongitude += increment
                if (currentLongitude > 179.500){
                    currentLongitude = -179.000
                }
            }
            if (currentLongitude > -95.100) {
                currentLongitude += increment
                currentLongitude += increment
            }
            if (currentLatitude >= -39.000 && currentLatitude <= 37.0000){
                currentLatitude += increment
                currentLatitude += increment
            }
            if (currentLatitude >= 37.04999999999998 && currentLongitude >= -95.100){
                australia = false
                southAmerica = false
                europe = false
                america = true
                currentLatitude = 37.0000
                currentLongitude = -95.000
                waitUntil = currentFireDate.addingTimeInterval(5.0)
            }
        }
        region.center.longitude = currentLongitude
        region.center.latitude = currentLatitude
        centerLocation.latitude = currentLatitude
        centerLocation.longitude = currentLongitude
    }
}

struct MapView: View {
    @ObservedObject var locationManager = LocationManager()
    var body: some View {
        
        SwiftUIMapView(centerLocation: $locationManager.centerLocation)
            .onAppear {
                locationManager.start()
            }
    }
}

struct SwiftUIMapView : UIViewRepresentable {
    @Binding var centerLocation : CLLocationCoordinate2D

    func makeUIView(context: Context) -> MKMapView {
        let mapView = MKMapView()
        return mapView
    }
    
    func updateUIView(_ uiView: MKMapView, context: Context) {
        uiView.centerCoordinate = centerLocation
    }
}

這是發生的事情:

  1. 位置現在由 ObservableObject LocationManager 控制
  2. start()上,每 1/30 秒觸發一次的發布者被觸發
  3. 每次火災時,它都會調用moveLocation()
  4. moveLocation想要暫停時,它會在發布者觸發的最后一個日期之前設置waitUntil 5 秒
  5. 如果發布者被解雇並且時間在waitUntil之前,它只是返回並等待下一次觸發

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM