Map icon indicating copy to clipboard operation
Map copied to clipboard

Share knowledge on maintaining SwiftUI frames

Open allenhumphreys opened this issue 1 year ago • 19 comments

These changes achieve 2 main things:

  1. The SwiftUI view's correctly follow the MKMapAnnotationView's frame around on the map. This fixes using onTapGesture directly on the SwiftUI view that represents the annotation
  2. The hosted SwiftUI is now updated (when Map is re-evaluated, which means when coordinateRegion changes, the annotations will be re-calculated. This allows hosting views that have inputs.

The result can be something like this:

https://user-images.githubusercontent.com/8225090/224500047-a4eb805e-f491-4303-a42c-8f66b1a13df1.mov

struct AnnotationPinView: View {
    let isSelected: Bool

    var body: some View {
        Image(systemName: "mappin")
            .renderingMode(.template)
            .aspectRatio(contentMode: .fit)
            .frame(width: 30, height: 30)
            .background(.green)
            .shadow(color: .black.opacity(0.5), radius: 0.9, x: 0.0, y: 2.0)
            .clipShape(Circle())
        // Note: Scale effect does not change intrinsicContentSize on the hosting view
            .scaleEffect(isSelected ? 1.5 : 1, anchor: .bottom)
            .animation(.interpolatingSpring(stiffness: 300, damping: 15, initialVelocity: 30), value: isSelected)
            .foregroundColor(isSelected ? .yellow : .blue)
    }
}
Map(
    coordinateRegion: $coordinateRegion,
    annotationItems: items,
    annotationContent: { itemModel in
        ViewMapAnnotation(
            coordinate: itemModel.coordinate,
            anchorPoint: CGPoint(x: 0.5, y: 1.0)
        ) {
            AnnotationPinView(isSelected: currentItem.id == itemModel.id)
                .onTapGesture {
                    currentItem = itemModel
                }
        }
    }
)
.ignoresSafeArea()

allenhumphreys avatar Mar 11 '23 17:03 allenhumphreys