Я пытаюсь анимировать аннотации к карте, когда они появляются, с помощью интерактивной пружины. Но в настоящее время никакой анимации не происходит. Фактическая метка аннотации не принимает никаких модификаторов представления, таких как .animation или .transition, поэтому вместо этого я размещаю их на своей пользовательской метке. Как я могу анимировать метку с помощью увеличения масштаба в сочетании с пружинистым движением?
struct LocationsView: View {
@EnvironmentObject private var vm: LocationsViewModel
@State var showStories: Bool = false
var body: some View {
ZStack {
mapLayer.ignoresSafeArea()
}
}
private var mapLayer: some View {
MapReader { mapProxy in
Map(position: $vm.mapCameraPosition) {
if showStories {
ForEach(vm.locations) { location in
Annotation(
location.shouldShowName ? location.name : "",
coordinate: location.coordinates) {
Circle().foregroundStyle(.red).frame(width: 50, height: 50)
.transition(.scale.combined(with: .identity))
.animation(.interpolatingSpring(stiffness: 0.5, damping: 0.5), value: showStories)
}
}
}
}
.onTapGesture {
showStories.toggle()
}
.onMapCameraChange(frequency: .continuous) { context in
guard let center = mapProxy.convert(context.region.center, to: .local) else { return }
for i in vm.locations.indices {
if let point = mapProxy.convert(vm.locations[i].coordinates, to: .local) {
vm.locations[i].shouldShowName = abs(point.x - center.x) < 250 && abs(point.y - center.y) < 250
} else {
vm.locations[i].shouldShowName = false
}
}
}
}
}
}
class LocationsViewModel: ObservableObject {
@Published var locations: [LocationMap] // All loaded locations
@Published var mapLocation: LocationMap { // Current location on map
didSet {
updateMapRegion(location: mapLocation)
}
}
@Published var mapCameraPosition = MapCameraPosition.automatic
let mapSpan = MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1)
init() {
let locations = LocationsDataService.locations
self.locations = locations
self.mapLocation = locations.first!
self.updateMapRegion(location: locations.first!)
}
private func updateMapRegion(location: LocationMap) {
withAnimation(.easeInOut) {
mapCameraPosition = .region(MKCoordinateRegion(
center: location.coordinates,
span: mapSpan))
}
}
func showNextLocation(location: LocationMap) {
withAnimation(.easeInOut) {
mapLocation = location
}
}
}
struct LocationMap: Identifiable {
let id: String = UUID().uuidString
let name: String
let cityName: String
let coordinates: CLLocationCoordinate2D
var shouldShowName = false
}
class LocationsDataService {
static let locations: [LocationMap] = [
LocationMap(name: "Colosseum", cityName: "Rome", coordinates: CLLocationCoordinate2D(latitude: 41.8902, longitude: 12.4922)),
LocationMap(name: "Pantheon", cityName: "Rome", coordinates: CLLocationCoordinate2D(latitude: 41.8986, longitude: 12.4769)),
LocationMap(name: "Trevi Fountain", cityName: "Rome", coordinates: CLLocationCoordinate2D(latitude: 41.9009, longitude: 12.4833))
]
}
struct SwiftfulMapAppApp: View {
@StateObject private var vm = LocationsViewModel()
var body: some View {
VStack {
LocationsView().environmentObject(vm)
}
}
}
Появление и исчезновение Annotation
нельзя анимировать. Вместо этого вам следует анимировать представление.
Поставьте if
вокруг Circle
, а не Annotation
:
Map(position: $vm.mapCameraPosition) {
ForEach(vm.locations) { location in
Annotation(
location.shouldShowName && showStories ? location.name : "",
coordinate: location.coordinates
) {
// this ZStack here so that the we have somewhere to put the .animation modifier
ZStack {
if showStories {
Circle().foregroundStyle(.red)
.transition(.scale)
}
}
.frame(width: 50, height: 50)
// .animation can't go on the Circle because it will disappear
.animation(.bouncy, value: showStories)
}
}
}
Если вы хотите анимировать только появление аннотаций, но не их исчезновение, вы можете оставить if
вокруг аннотаций и написать собственное представление, которое анимирует само себя onAppear
.
Map(position: $vm.mapCameraPosition) {
if showStories {
ForEach(vm.locations) { location in
Annotation(
location.shouldShowName ? location.name : "",
coordinate: location.coordinates) {
AnnotationCircle()
}
}
}
}
struct AnnotationCircle: View {
@State var scale = 0.0
var body: some View {
Circle()
.foregroundStyle(.red)
.transition(.scale)
.frame(width: 50, height: 50)
.scaleEffect(scale)
.animation(.bouncy, value: scale)
.onAppear {
scale = 1.0
}
.onDisappear {
scale = 0.0
}
}
}
Исчезновение не будет анимировано, поскольку аннотация удаляется немедленно, прежде чем представление сможет что-либо анимировать.
Спасибо. Не могли бы вы посмотреть это: stackoverflow.com/questions/78742726/clip-view-on-drag-swift-ui