You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 18:54:00