Маркеры карты обрезаются при применении ignoreSafeArea() с помощью Google Map.IOS

Программируем под IOS
Ответить
Anonymous
 Маркеры карты обрезаются при применении ignoreSafeArea() с помощью Google Map.

Сообщение Anonymous »

Я использую iOS Google Maps SDK для отображения карт в своем приложении.
На моих картах я также показываю некоторые маркеры карты.
Это работает отлично, однако я хочу, чтобы карта игнорировала безопасные области устройства, чтобы она растягивалась на всю высоту (за любыми вырезами и нижними панелями вкладок).
Проблема, с которой я сталкиваюсь, заключается в том, что при применении .ignoresSafeArea() на карту, все мои маркеры на карте обрезаются, например:
Изображение

Это происходит только тогда, когда я добавляю .ignoresSafeArea(). Без него маркеры отображаются нормально.
Я не уверен, что делаю неправильно.
Вот мой код SwiftUI, который показывает карту:
import GoogleMaps

struct MapView: View {

@EnvironmentObject var apiManager: ApiManager

private var mapOptions: GMSMapViewOptions {
var options = GMSMapViewOptions()
return options
}

var body: some View {
ZStack {
GoogleMapView(options: mapOptions)
.mapMarkers(MapHelper.convertToGoogleMarkers(markers: apiManager.markers))
.ignoresSafeArea()
}
.task {
getMapMarkers()
}
.navigationBarHidden(true)
}

func getMapMarkers() {
Task {
await apiManager.fetchAllMapMarkers()
}
}
}

А вот UIViewRepresentable для GoogleMapView:
import SwiftUI
import GoogleMaps

/// A SwiftUI wrapper for GMSMapView that displays a map with optional markers and configurable map type
struct GoogleMapView: UIViewRepresentable {

// Configuration properties - set at initialization
private let options: GMSMapViewOptions

/// Array of markers to display on the map
private var markers: [GMSMarker]

/// Type of map to display (normal, satellite, hybrid, terrain)
private let mapType: GMSMapViewType

// Runtime updatable properties
private var camera: GMSCameraPosition?
private var backgroundColor: UIColor?

/// Shared delegate instance to handle map interactions across all instances
/// Using static ensures callbacks work together when chaining modifiers
private static let mapDelegate = GoogleMapViewDelegate()

init(options: GMSMapViewOptions,
markers: [GMSMarker] = [],
mapType: GMSMapViewType = .normal) {
self.options = options
self.markers = markers
self.mapType = mapType
}

/// Creates the underlying UIKit map view
func makeUIView(context: Context) -> GMSMapView {
// Initialize map with current options
let mapView = GMSMapView(options: options)
mapView.overrideUserInterfaceStyle = .unspecified
mapView.mapType = mapType

// Set shared delegate to handle interactions
mapView.delegate = Self.mapDelegate

return mapView
}

/// Updates the map view when SwiftUI state changes
func updateUIView(_ uiView: GMSMapView, context: Context) {
// Update runtime properties if set
if let camera = camera {
uiView.camera = camera
}

if let backgroundColor = backgroundColor {
uiView.backgroundColor = backgroundColor
}

//clears all markers and polylines
uiView.clear()

// Refresh markers on the map
markers.forEach { marker in
marker.map = uiView
}

uiView.mapType = mapType // Update map type if changed
}
}

class GoogleMapViewDelegate: NSObject, GMSMapViewDelegate {

var tapHandler: ((CLLocationCoordinate2D) -> Void)?
var markerTapHandler: ((GMSMarker) -> Bool)?

/// Called by GMSMapView when user taps the map at a specific coordinate
/// - Parameters:
/// - mapView: The GMSMapView that detected the tap
/// - coordinate: The geographic coordinate where the tap occurred
func mapView(_ mapView: GMSMapView, didTapAt coordinate: CLLocationCoordinate2D) {
tapHandler?(coordinate) // Forward tap to handler if one is set
}

/// Called by GMSMapView when user taps a marker on the map
/// - Parameters:
/// - mapView: The GMSMapView that detected the tap
/// - marker: The GMSMarker that was tapped
/// - Returns: true if tap was handled by the app, false to allow default marker behavior
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
return markerTapHandler?(marker) ?? false // Forward to handler or use default behavior
}

}

// MARK: - viewModifiers and Markers

extension GoogleMapView {
/// Updates the camera position of the map view during runtime
/// - Parameter position: New camera position to apply
/// - Returns: Updated GoogleMapView instance
func camera(_ position: GMSCameraPosition?) -> GoogleMapView {
var view = self
if let position = position {
view.camera = position
}
return view
}

/// Updates the background color of the map view during runtime
/// - Parameter color: New background color to apply
/// - Returns: Updated GoogleMapView instance
func backgroundColor(_ color: UIColor) -> GoogleMapView {
var view = self
view.backgroundColor = color
return view
}

/// Changes the map display type
/// - Parameter type: GMSMapViewType to use (.normal, .satellite, etc)
/// - Returns: New GoogleMapView instance with updated map type
func mapType(_ type: GMSMapViewType) -> GoogleMapView {
GoogleMapView(options: options, markers: markers, mapType: type)
}

/// Adds markers to the map
/// - Parameter markers: Array of GMSMarker objects to display
/// - Returns: New GoogleMapView instance with updated markers
func mapMarkers(_ markers: [GMSMarker]) -> GoogleMapView {
var view = self
view.markers = markers
return view
}

}

// MARK: - View Callbacks

extension GoogleMapView {
/// Adds handler for map tap events
/// - Parameter handler: Closure called when map is tapped, providing tap coordinates
/// - Returns: Same GoogleMapView instance with updated tap handler
func onMapTapped(_ handler: @escaping (CLLocationCoordinate2D) -> Void) -> GoogleMapView {
Self.mapDelegate.tapHandler = handler
return self
}

/// Adds handler for marker tap events
/// - Parameter handler: Closure called when marker is tapped
/// - Returns: Same GoogleMapView instance with updated marker handler
/// Return true from handler to indicate tap was handled
func onMarkerTapped(_ handler: @escaping (GMSMarker) -> Bool) -> GoogleMapView {
Self.mapDelegate.markerTapHandler = handler
return self
}
}

extension View {
/// Configures the view to ignore safe areas except for the top
/// Useful for map views that should fill the screen below status bar
/// - Returns: Modified view that extends to screen edges except top
func ignoresSafeAreaExceptTop() -> some View {
ignoresSafeArea(.container, edges: [.bottom, .horizontal])
}
}

Наконец, вот моя функция ConvertToGoogleMarkers():
static func convertToGoogleMarkers(markers: Array, showOrder: Bool = false) -> Array {
return markers.enumerated().map { (index, mapMarker) in
let marker = GMSMarker(position: CLLocationCoordinate2D(
latitude: Double(mapMarker.latitude)!,
longitude: Double(mapMarker.longitude)!
))

// Set the Place as the userData
marker.userData = mapMarker

let markerView = MarkerUIView(marker: mapMarker, showOrder: showOrder)

let size = markerView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
markerView.frame = CGRect(origin: .zero, size: size)

marker.iconView = markerView

if let order = mapMarker.order {
if (mapMarker.date != nil) {
marker.zIndex = Int32(10000 - order)
} else {
marker.zIndex = Int32(1000 - order)
}
}

return marker
}
}


Изменить:
Похоже, что если я закомментирую этот код из моей функции ConvertToGoogleMarkers(), маркеры карт Google по умолчанию будут отображаться нормально. В чем может быть проблема с моими собственными маркерами?
// let markerView = MarkerUIView(marker: mapMarker, showOrder: showOrder)
//
// let size = markerView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
// markerView.frame = CGRect(origin: .zero, size: size)
//
// marker.iconView = markerView

Вот мой MapMarkerView:
import SwiftUI
import MapKit

struct MapMarkerView: View {
var marker: MapMarker2
var showOrder: Bool = false

let circleBorderWidth: CGFloat = 4

var body: some View {
VStack(spacing: 0) {
ZStack {
let color = marker.hexColor != nil ? Color(hex: marker.hexColor!) : Color.wireframe

if (showOrder && marker.date != nil) {
Circle()
.fill(color)
.frame(width: 40, height: 40)
.shadow(color: .black.opacity(0.1), radius: 4, x: 0, y: 4)
.overlay(
Circle()
.inset(by: circleBorderWidth / 2)
.stroke(Color.mapMarkerBackground, lineWidth: circleBorderWidth)
)

if let order = marker.order {
Text("\(order)")
.font(.custom("Inter-SemiBold", size: 18))
.foregroundColor(Color.white)
}
} else {
Circle()
.fill(Color.mapMarkerBackground)
.frame(width: 40, height: 40)
.shadow(color: .black.opacity(0.1), radius: 4, x: 0, y: 4)
.overlay(
ZStack {
Circle()
.fill(color)
.opacity(0.33)

Circle()
.inset(by: circleBorderWidth / 2)
.stroke(Color.mapMarkerBackground, lineWidth: circleBorderWidth)
}
)

AsyncImage(url: URL(string: marker.iconUrl ?? "")) { image in
image.resizable()
.frame(width: 24, height: 24)
} placeholder: {
Circle()
.fill(Color.mapMarkerBackground)
.frame(width: 40, height: 40)
}
}
}

Triangle()
.rotationEffect(.degrees(-180))
.foregroundColor(Color.mapMarkerBackground)
.frame(width: 12, height: 10)
.offset(y: -4)
}
}
}

class MarkerUIView: UIView {
private var hostingController: UIHostingController?
private var onTapAction: (() -> Void)?

init(marker: MapMarker2, showOrder: Bool = false) {
super.init(frame: .zero)

// Use AnyView so we can capture the binding
self.hostingController = UIHostingController(
rootView: AnyView(MapMarkerView(marker: marker, showOrder: showOrder))
)

guard let hostingView = hostingController?.view else { return }

// Make background transparent
hostingView.backgroundColor = .clear

// Add the SwiftUI view to the UIView hierarchy
addSubview(hostingView)

// Size the hosting controller's view
hostingView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
hostingView.leadingAnchor.constraint(equalTo: leadingAnchor),
hostingView.trailingAnchor.constraint(equalTo: trailingAnchor),
hostingView.topAnchor.constraint(equalTo: topAnchor),
hostingView.bottomAnchor.constraint(equalTo: bottomAnchor)
])

sizeToFit()
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

// Forward tap to the SwiftUI view
override func touchesEnded(_ touches: Set, with event: UIEvent?) {
onTapAction?()
super.touchesEnded(touches, with: event)
}
}


Подробнее здесь: https://stackoverflow.com/questions/797 ... google-map
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «IOS»