如何在用户触摸 SwiftUI 中的 GoogleMaps 标记时更改 UI 状态?
How to change UI state when user touch GoogleMaps' Marker in SwiftUI?
这个问题是关于 SwiftUI 的。
我正在尝试显示地图并允许用户触摸任何可用的标记。当它发生时,我希望更改我视图中的文本,以反映该用户的操作。
经过大量搜索,我认为解决方案可以接近 Observable 协议,但我就是想不出正确的方法。这是我的代码:
struct Home: View {
// Here's the attribute I want to be changed when user touches the marker
var selectedMarker: GMSMarker?
var body: some View {
VStack(spacing: 0) {
// Condition to be applied when user touches the marker
if (selectedMarker == nil){
Text("No marker selected").padding()
}else{
Text("Now, there's a marker selected").padding()
}
GoogleMapsHome()
}
.navigationBarBackButtonHidden(true)
.navigationBarTitle(Text("Marker question"), displayMode: .inline)
}
}
struct Home_Previews: PreviewProvider {
static var previews: some View {
Home()
}
}
这是 GoogleMaps 定义:
struct GoogleMapsHome: UIViewRepresentable {
private let zoom: Float = 18
// Just for didactic purposes. Later, I'm going to use LocationManager
let lat: Double = -15.6692660716233
let lng: Double = -47.83980712156295
func makeUIView(context: Self.Context) -> GMSMapView {
let camera = GMSCameraPosition.camera(
withLatitude: lat,
longitude: lng,
zoom: zoom)
let mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
mapView.mapType = .hybrid
mapView.delegate = context.coordinator
return mapView
}
func updateUIView(_ mapView: GMSMapView, context: Context) {
mapView.animate(toLocation: CLLocationCoordinate2D(latitude: lat, longitude: lng))
let position = CLLocationCoordinate2D(latitude: lat, longitude: lng)
let marker = GMSMarker(position: position)
marker.title = "You"
marker.map = mapView
}
func makeCoordinator() -> Coordinator {
Coordinator(owner: self)
}
class Coordinator: NSObject, GMSMapViewDelegate, ObservableObject {
let owner: GoogleMapsHome // access to owner view members,
init(owner: GoogleMapsHome) {
self.owner = owner
}
@Published var selectedMarker: GMSMarker? {
willSet { objectWillChange.send() }
}
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
print("A marker has been touched by the user")
self.selectedMarker = marker
return true
}
}
}
我希望有人能帮助我,以后这个问题对任何有同样需求的人都有用。
此致!
过了一段时间,我找到了解决的方法。
关键字是 "Coordinator" 和 "Binding"。
当然,我不确定这是正确的方法还是最好的方法,但至少它有效。
import Foundation
import SwiftUI
import GoogleMaps
struct Home: View {
@State var selectedMarker: GMSMarker?
var body: some View {
VStack(spacing: 0) {
if (selectedMarker == nil){
Text("No marker selected").padding()
}else{
Text("There's a marker selected").padding()
}
GoogleMapsHome(selectedMarker: self.$selectedMarker)
}
.navigationBarBackButtonHidden(true)
.navigationBarTitle(Text("Map Test"), displayMode: .inline)
}
}
struct Home_Previews: PreviewProvider {
static var previews: some View {
Home()
}
}
struct GoogleMapsHome: UIViewRepresentable {
private let zoom: Float = 18
let lat: Double = -15.6692660716233
let lng: Double = -47.83980712156295
@Binding var selectedMarker: GMSMarker?
func makeCoordinator() -> Coordinator {
return Coordinator(
owner: self,
selectedMarker: $selectedMarker)
}
func makeUIView(context: Self.Context) -> GMSMapView {
let camera = GMSCameraPosition.camera(
withLatitude: lat,
longitude: lng,
zoom: zoom)
let mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
mapView.mapType = .hybrid
mapView.delegate = context.coordinator
return mapView
}
func updateUIView(_ mapView: GMSMapView, context: Context) {
mapView.animate(toLocation: CLLocationCoordinate2D(latitude: lat, longitude: lng))
let position = CLLocationCoordinate2D(latitude: lat, longitude: lng)
let marker = GMSMarker(position: position)
marker.title = "You"
marker.map = mapView
}
class Coordinator: NSObject, GMSMapViewDelegate, ObservableObject {
let owner: GoogleMapsHome // access to owner view members,
@Binding var selectedMarker: GMSMarker?
init(
owner: GoogleMapsHome,
selectedMarker: Binding<GMSMarker?>
) {
self.owner = owner
_selectedMarker = selectedMarker
}
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
print("A marker has been touched")
self.selectedMarker = marker
return true
}
}
}
这个问题是关于 SwiftUI 的。
我正在尝试显示地图并允许用户触摸任何可用的标记。当它发生时,我希望更改我视图中的文本,以反映该用户的操作。
经过大量搜索,我认为解决方案可以接近 Observable 协议,但我就是想不出正确的方法。这是我的代码:
struct Home: View {
// Here's the attribute I want to be changed when user touches the marker
var selectedMarker: GMSMarker?
var body: some View {
VStack(spacing: 0) {
// Condition to be applied when user touches the marker
if (selectedMarker == nil){
Text("No marker selected").padding()
}else{
Text("Now, there's a marker selected").padding()
}
GoogleMapsHome()
}
.navigationBarBackButtonHidden(true)
.navigationBarTitle(Text("Marker question"), displayMode: .inline)
}
}
struct Home_Previews: PreviewProvider {
static var previews: some View {
Home()
}
}
这是 GoogleMaps 定义:
struct GoogleMapsHome: UIViewRepresentable {
private let zoom: Float = 18
// Just for didactic purposes. Later, I'm going to use LocationManager
let lat: Double = -15.6692660716233
let lng: Double = -47.83980712156295
func makeUIView(context: Self.Context) -> GMSMapView {
let camera = GMSCameraPosition.camera(
withLatitude: lat,
longitude: lng,
zoom: zoom)
let mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
mapView.mapType = .hybrid
mapView.delegate = context.coordinator
return mapView
}
func updateUIView(_ mapView: GMSMapView, context: Context) {
mapView.animate(toLocation: CLLocationCoordinate2D(latitude: lat, longitude: lng))
let position = CLLocationCoordinate2D(latitude: lat, longitude: lng)
let marker = GMSMarker(position: position)
marker.title = "You"
marker.map = mapView
}
func makeCoordinator() -> Coordinator {
Coordinator(owner: self)
}
class Coordinator: NSObject, GMSMapViewDelegate, ObservableObject {
let owner: GoogleMapsHome // access to owner view members,
init(owner: GoogleMapsHome) {
self.owner = owner
}
@Published var selectedMarker: GMSMarker? {
willSet { objectWillChange.send() }
}
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
print("A marker has been touched by the user")
self.selectedMarker = marker
return true
}
}
}
我希望有人能帮助我,以后这个问题对任何有同样需求的人都有用。
此致!
过了一段时间,我找到了解决的方法。
关键字是 "Coordinator" 和 "Binding"。
当然,我不确定这是正确的方法还是最好的方法,但至少它有效。
import Foundation
import SwiftUI
import GoogleMaps
struct Home: View {
@State var selectedMarker: GMSMarker?
var body: some View {
VStack(spacing: 0) {
if (selectedMarker == nil){
Text("No marker selected").padding()
}else{
Text("There's a marker selected").padding()
}
GoogleMapsHome(selectedMarker: self.$selectedMarker)
}
.navigationBarBackButtonHidden(true)
.navigationBarTitle(Text("Map Test"), displayMode: .inline)
}
}
struct Home_Previews: PreviewProvider {
static var previews: some View {
Home()
}
}
struct GoogleMapsHome: UIViewRepresentable {
private let zoom: Float = 18
let lat: Double = -15.6692660716233
let lng: Double = -47.83980712156295
@Binding var selectedMarker: GMSMarker?
func makeCoordinator() -> Coordinator {
return Coordinator(
owner: self,
selectedMarker: $selectedMarker)
}
func makeUIView(context: Self.Context) -> GMSMapView {
let camera = GMSCameraPosition.camera(
withLatitude: lat,
longitude: lng,
zoom: zoom)
let mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
mapView.mapType = .hybrid
mapView.delegate = context.coordinator
return mapView
}
func updateUIView(_ mapView: GMSMapView, context: Context) {
mapView.animate(toLocation: CLLocationCoordinate2D(latitude: lat, longitude: lng))
let position = CLLocationCoordinate2D(latitude: lat, longitude: lng)
let marker = GMSMarker(position: position)
marker.title = "You"
marker.map = mapView
}
class Coordinator: NSObject, GMSMapViewDelegate, ObservableObject {
let owner: GoogleMapsHome // access to owner view members,
@Binding var selectedMarker: GMSMarker?
init(
owner: GoogleMapsHome,
selectedMarker: Binding<GMSMarker?>
) {
self.owner = owner
_selectedMarker = selectedMarker
}
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
print("A marker has been touched")
self.selectedMarker = marker
return true
}
}
}