iOS 17中位置更新引发Toolbar菜单意外消失问题(关联菜单内容)
iOS 17位置更新导致Toolbar菜单意外关闭的问题
问题描述
我的App需要追踪用户位置,但每次locationManager发送位置更新时,若Toolbar菜单处于展开状态就会被意外关闭。奇怪的是,若菜单按钮的操作是空实现或仅包含print语句则无此问题,一旦调用实际方法(哪怕是空方法help()),下次UI更新时菜单就会消失。
环境信息
- iOS: 17.0
- Xcode: Version 15.0 beta 3
- 后台模式: Location updates
- 隐私权限配置:
Privacy - Location When In Use Usage Description = You are being watched!
相关代码
import SwiftUI @main struct DetectHelpApp: App { var locationManager = LocationManager() var body: some Scene { WindowGroup { ContentView() .environment(locationManager) } } } import MapKit struct ContentView: View { @Environment(LocationManager.self) var locationManager @State private var cameraPosition: MapCameraPosition = .region(MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 51.556000, longitude: -0.279511), latitudinalMeters: 1000, longitudinalMeters: 1000)) var body: some View { NavigationStack { Map(position: $cameraPosition) { UserAnnotation() } .onChange(of: locationManager.lastLocation) { oldValue, newValue in print(locationManager.lastLocation) withAnimation() { cameraPosition = .region(MKCoordinateRegion(center: newValue.coordinate, latitudinalMeters: 1000, longitudinalMeters: 1000)) } } // onChange - end .toolbar { ToolbarItem(placement: .topBarTrailing) { Menu("Menu") { Button("Start") { help() /*print("Start")*/ } // <-- *** 问题触发点 *** Button("Resume") { print("Resume") } } } } .navigationTitle("Scooby Doo") } } func help() { } } import CoreLocation import Observation @Observable final class LocationManager: NSObject, CLLocationManagerDelegate { var lastLocation: CLLocation = CLLocation(latitude: 51.556000, longitude: -0.279511) let locationManager = CLLocationManager() init(dog: String = "") { super.init() locationManager.delegate = self locationManager.desiredAccuracy = kCLLocationAccuracyBest locationManager.distanceFilter = 2 locationManager.requestWhenInUseAuthorization() locationManager.requestAlwaysAuthorization() locationManager.startUpdatingLocation() } func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { // Ensure we have an actual location in the update. guard let location = locations.last else { return } lastLocation = location // Our published CLLocation. } }
解决方案
原因分析
这是iOS 17 + Xcode 15 beta版本中SwiftUI的一个已知行为:当@Observable对象的属性更新触发视图刷新时,展开的Menu组件会因为视图重新渲染而被自动重置关闭。当按钮动作仅包含print时,SwiftUI会优化视图状态,不会标记视图需要完全刷新;但调用自定义方法时,会触发视图状态的更新标记,导致后续位置更新时视图完全重绘,进而关闭菜单。
修复方案:手动控制菜单展开状态
通过@State变量手动跟踪Menu的展开状态,避免视图刷新时自动关闭:
- 在
ContentView中添加状态变量:
@State private var isMenuExpanded = false
- 修改Toolbar部分的Menu实现:
.toolbar { ToolbarItem(placement: .topBarTrailing) { // 使用isPresented绑定手动控制菜单状态 Menu("Menu", isPresented: $isMenuExpanded) { Button("Start") { help() // 执行完操作后手动关闭菜单 isMenuExpanded = false } Button("Resume") { print("Resume") isMenuExpanded = false } } } }
额外优化建议
- 如果
help()方法涉及异步操作,可将其放在Task中执行,避免阻塞UI线程导致意外状态变化。 - 适当增大
locationManager.distanceFilter的值,减少不必要的位置更新频率,降低视图刷新次数。
内容的提问来源于stack exchange,提问作者Magnas
相关产品推荐
相关产品推荐

