[英]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
}
}
這是發生的事情:
start()
上,每 1/30 秒觸發一次的發布者被觸發moveLocation()
moveLocation
想要暫停時,它會在發布者觸發的最后一個日期之前設置waitUntil
5 秒waitUntil
之前,它只是返回並等待下一次觸發
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.