[英]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.