SwiftUI:避免使用 MKMapView+UIViewRepresentable 在 TabView 中重新创建/重新渲染视图
Posted
技术标签:
【中文标题】SwiftUI:避免使用 MKMapView+UIViewRepresentable 在 TabView 中重新创建/重新渲染视图【英文标题】:SwiftUI: avoid recreating/rerendering view in TabView with MKMapView+UIViewRepresentable 【发布时间】:2019-09-25 07:30:17 【问题描述】:我有一个带有三个选项卡的 TabView,其中一个包含这样实现的地图视图:
struct MapView: UIViewRepresentable
let region: MKCoordinateRegion
let animatedRegion: Bool
func makeUIView(context: Context) -> MKMapView
let mapView = MKMapView(frame: .zero)
mapView.delegate = context.coordinator
mapView.showsUserLocation = true
mapView.setRegion(region, animated: animatedRegion)
return mapView
func makeCoordinator() -> Coordinator
Coordinator(self)
func updateUIView(_ mapView: MKMapView, context: Context)
class Coordinator: NSObject, MKMapViewDelegate
var control: MapView
init(_ control: MapView)
self.control = control
标签视图是这样实现的:
TabView(selection: $selection)
MapView(/* params */)
.tabItem
Image(systemName: "1.square.fill")
Text("map")
.tag(1)
Text("Screen #2")
.tabItem
Image(systemName: "2.square.fill")
Text("2")
.tag(2)
Text("Screen #3")
.tabItem
Image(systemName: "3.square.fill")
Text("3")
.tag(3)
问题是每次我从其他两个选项卡之一切换回地图选项卡时都会执行 makeUIView(:context) 方法。当我切换到另一个选项卡时,似乎底层的 MKMapView 实例被释放,然后当我切换回来时它被重新创建。在 UIKit 中,它不会像那样重新渲染整个视图。我做错了什么,或者我可以做些什么来确保在我切换回来时保留底层的 MKMapView 实例,这样它就不必每次都重新创建它?
【问题讨论】:
【参考方案1】:您需要为每个选项卡存储MKMapView
的实例并在离开视图之前销毁,因为 SwiftUI 在需要渲染时会销毁 MapView,例如绑定变量已更改。
struct MapView: UIViewRepresentable
@Binding var currentTab: Int
static private var mapViews = [Int: MKMapView]()
let region: MKCoordinateRegion
let animatedRegion: Bool
func makeUIView(context: Context) -> MKMapView
guard MapView.mapViews[currentTab] != nil else return MapView.mapViews[currentTab]!
let mapView = MKMapView(frame: .zero)
mapView.delegate = context.coordinator
mapView.showsUserLocation = true
mapView.setRegion(region, animated: animatedRegion)
MapView.mapViews[currentTab] = mapView
return mapView
func makeCoordinator() -> Coordinator
Coordinator(self)
func updateUIView(_ mapView: MKMapView, context: Context)
class Coordinator: NSObject, MKMapViewDelegate
var control: MapView
init(_ control: MapView)
self.control = control
【讨论】:
太棒了,我对您的代码进行了稍微修改的版本,符合我的需要,效果很好。 pastebin.com/pyYStaHn 我会将mapView.setRegion(region, animated: animatedRegion)
移动到updateUIView
,因为如果region
发生更改,那么 setRegion 将不会运行。【参考方案2】:
使用环境对象。总是更新它并在 TabView MapView(coordinates: Object.coordinates)
中传递它【讨论】:
以上是关于SwiftUI:避免使用 MKMapView+UIViewRepresentable 在 TabView 中重新创建/重新渲染视图的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI 上的按钮点击调用 MKMapView.setRegion
无法将点击手势识别器添加到 SwiftUI MKMapView UIViewRepresentable