jma*_*101 6 dictionary mkannotation swift swiftui
我很好奇当你需要在 SwiftUI 中的 Map 上有一堆自定义注释时,最佳实践是什么。这是我的第一个真正的 IOS 项目,所以我的边缘有点粗糙。目前,我有 2400 个注释,它们是带有自定义图像的按钮,最终,当用户单击它们时,它们会弹出有关艺术品的信息。
到目前为止,我所做的是将每个引脚的所有数据放入 CoreData 中,并与其所代表的实体建立正确的关系,以及直接从 MapAnnotation 内容在我的资产文件夹中调用的图像字符串。
我在自己的 iPhone 8 上运行过。FPS 明显下降。不知道是不是因为注释量很大,但是那是不会往下掉的。这是我的 MapView() 的示例
仅供参考,我在 onAppear() 上获取引脚,按钮上也将有一个过滤器。代码还远远没有完成,只是试图在走得太远而无法返回之前解决一个问题。
感谢您的任何意见。祝你有美好的一天
导入 SwiftUI 导入 MapKit 导入 CoreData
结构MapView:视图{
@Environment(\.managedObjectContext) private var moc
@State var pins: [Pin] = []
@State var userTrackingMode: MapUserTrackingMode = .follow
// Location for Montreal downtown
@State var region = MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: 45.50240, longitude: -73.57067),
span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
var body: some View {
ZStack{
Map(coordinateRegion: $region,
interactionModes: MapInteractionModes.all,
showsUserLocation: true,
userTrackingMode: $userTrackingMode,
annotationItems: pins)
{ pin in
MapAnnotation(coordinate: CLLocationCoordinate2D(
latitude: pin.location?.latitude ?? 0,
longitude: pin.location?.longitude ?? 0))
{
Button(action: {
}){
if pin.isArtwork {
Image("\(pin.imageDefault!)")
.resizable()
.scaledToFit()
.frame(width: 10)
} else if pin.isPlace {
Image("\(pin.imageDefault ?? "place_pin")")
.resizable()
.scaledToFit()
.frame(width: 10)
}
}
}
}
.accentColor(Color.blue)
HStack(alignment: .bottom){
Spacer()
VStack(alignment: .trailing){
Spacer()
Button(action: {userTrackingMode = .follow}) {
Image("user_location")
.resizable()
.scaledToFit()
.frame(width: 40.0)
}
.padding()
.padding(.bottom, -20)
.cornerRadius(10)
.shadow(radius: /*@START_MENU_TOKEN@*/10/*@END_MENU_TOKEN@*/)
VStack{
Button(action: {
pins = fetchPins(predicate: "isArtwork == false")
}) {
Image("map_filter")
.resizable()
.scaledToFit()
.frame(width: 40.0)
}
.cornerRadius(10)
.shadow(radius: /*@START_MENU_TOKEN@*/10/*@END_MENU_TOKEN@*/)
.padding()
.onAppear {
pins = fetchPins(predicate: nil)
}
}
}
.padding(.bottom, 50)
}
}
}
Run Code Online (Sandbox Code Playgroud)
}
扩展地图视图{
func fetchPins(predicate: String?) -> [Pin]{
do {
let request = Pin.fetchRequest() as NSFetchRequest<Pin>
if predicate != nil && predicate!.count > 0 {
let predicate = NSPredicate(format: predicate!)
request.predicate = predicate
}
return try moc.fetch(request)
} catch {
fatalError("Error fetching pin + predicate")
}
}
Run Code Online (Sandbox Code Playgroud)
}
我认为问题在于,每当区域发生变化时,视图就会重建,因此 SwiftUI 最终会不断刷新注释列表。
另一个答案消除了滞后,因为当区域更改时我们不再重建视图,但我注意到当注释列表更新时,地图区域会重置为初始值(这是有道理的,因为我们正在使用.constant(region))。为了避免这个问题,我做了以下事情。
首先,使用自定义绑定为该区域创建一个包装类。
class RegionWrapper {
var _region: MKCoordinateRegion = MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: 30, longitude: -90),
span: MKCoordinateSpan(latitudeDelta: 10, longitudeDelta: 10))
var region: Binding<MKCoordinateRegion> {
Binding(
get: { self._region },
set: { self._region = $0 }
)
}
}
Run Code Online (Sandbox Code Playgroud)
现在,在视图结构中,创建一个实例RegionWrapper并传递regionWrapper.region给地图。
这适用于大多数情况,但如果您想以编程方式更改区域,则必须进行一些额外的更改,以便重建视图。
首先,创建RegionWrapper一个ObservableObject,并添加一个@Published标志变量。最终的类应该是这样的:
class RegionWrapper: ObservableObject {
var _region: MKCoordinateRegion = MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: 30, longitude: -90),
span: MKCoordinateSpan(latitudeDelta: 10, longitudeDelta: 10))
var region: Binding<MKCoordinateRegion> {
Binding(
get: { self._region },
set: { self._region = $0 }
)
}
@Published var flag = false
}
Run Code Online (Sandbox Code Playgroud)
将视图结构中的变量更新为@StateObject. 现在,每当您想要更改区域时,首先设置regionWrapper.region.wrappedValue,然后调用regionWrapper.flag.toggle()以强制重建视图(您可以将它们包装起来withAnimation以实现更平滑的过渡)。示例视图如下。
struct MapView: View {
@StateObject private var regionWrapper = RegionWrapper()
var body: some View {
Map(coordinateRegion: regionWrapper.region, annotationItems: annotations) { ... }
}
func updateRegion(newRegion: MKCoordinateRegion) {
withAnimation {
regionWrapper.region.wrappedValue = newRegion
regionWrapper.flag.toggle()
}
}
}
Run Code Online (Sandbox Code Playgroud)
希望这对遇到此问题的人有所帮助。
小智 4
我遇到了与此类似的问题,并发现将区域从
coordinateRegion: $region
Run Code Online (Sandbox Code Playgroud)
到
coordinateRegion: .constant(region)
Run Code Online (Sandbox Code Playgroud)
停止了延迟,我仍然可以通过位置管理器更改区域
| 归档时间: |
|
| 查看次数: |
1443 次 |
| 最近记录: |