SwiftUI中使用Google Maps iOS SDK实现地图padding随底部弹窗动画
解决方案
你的代码无法产生动画的核心原因是:SwiftUI的动画事务不会自动应用到UIKit视图的属性修改上,GMSMapView的padding动画需要显式包裹在UIKit的UIView动画块中实现,同时要和底部底框的动画参数对齐,避免不同步的问题。
另外原有代码中把GMSMapView作为MapView结构体的存储属性写法不规范,UIViewRepresentable要求UIKit视图必须在makeUIView方法中创建,否则SwiftUI视图重绘时可能出现实例异常释放的问题,也已在下方代码中修正。
修改后的完整可运行代码如下:
import SwiftUI import GoogleMaps struct MapView: UIViewRepresentable { var bottomPadding: CGFloat func makeUIView(context: Context) -> GMSMapView { // 遵循UIViewRepresentable生命周期规范,在该方法内创建GMSMapView GMSMapView(frame: .zero) } func updateUIView(_ mapView: GMSMapView, context: Context) { let targetPadding = UIEdgeInsets(top: 0, left: 0, bottom: bottomPadding, right: 0) // 读取当前SwiftUI事务的动画配置,同步应用到UIKit动画,保证和底部底框动画节奏完全一致 if let animation = context.transaction.animation { UIView.animate( withDuration: animation.duration, delay: 0, options: .curveEaseInOut ) { mapView.padding = targetPadding } } else { // 无动画场景直接赋值 mapView.padding = targetPadding } } } struct ContentView: View { @State var showBottomSheet: ShowBottomSheet = .hidden var bottomSheetHeight: CGFloat { showBottomSheet == .visible ? showBottomSheet.rawValue : 0 } var body: some View { GeometryReader { geometry in ZStack { MapView(bottomPadding: geometry.size.height * bottomSheetHeight) .edgesIgnoringSafeArea(.all) .bottomSheet( bottomSheetPosition: $showBottomSheet, options: [ .allowContentDrag, .swipeToDismiss, .noBottomPosition, .shadow() ], content: {} ) } } } } enum ShowBottomSheet: CGFloat, CaseIterable { case hidden = 0, visible = 0.5 }
如果出现动画曲线和底部底框不匹配的情况,调整UIView.animate的options参数,替换为对应底框使用的动画曲线即可。
内容的提问来源于stack exchange,提问作者Angus
相关产品推荐
相关产品推荐

