Flutter中Google Map圆形波纹动画导致应用卡顿问题排查
Google Map Flutter 动画卡顿问题排查与解决
问题描述
在Flutter中使用Google Map组件实现多个圆形的缩放动画时,应用出现明显卡顿。尝试使用flutter_animarker库后问题依旧,不清楚是Google Map插件本身不支持动画,还是实现方式存在错误。
卡顿原因分析
从提供的代码来看,卡顿的核心原因在于不必要的全量重建和对象重复创建:
- AnimatedBuilder包裹整个GoogleMap:动画控制器每帧触发时,会重建整个GoogleMap组件,包括所有Marker和Circle,导致UI线程负载过高。
- Circle/Marker对象重复生成:每次动画帧都通过
map方法重新创建所有Circle和Marker实例,大量临时对象会触发频繁GC,进一步加剧卡顿。 - 无限循环动画持续触发重建:
AnimationController设置了repeat(),每800ms循环一次,持续触发全量重建,没有针对性的局部更新逻辑。
解决方案
1. 缩小动画更新范围
用ValueNotifier+ValueListenableBuilder替代AnimatedBuilder,仅针对需要动画的Circle部分做局部更新,避免整个GoogleMap重建:
2. 复用Circle对象
通过copyWith方法复用已有的Circle实例,只更新动画相关的属性(半径、透明度),减少对象创建开销。
修改后的代码示例
class GoogleMapInteg extends StatefulWidget { const GoogleMapInteg({super.key}); @override State<GoogleMapInteg> createState() => _GoogleMapIntegState(); } class _GoogleMapIntegState extends State<GoogleMapInteg> with SingleTickerProviderStateMixin { final CameraPosition ciaro = const CameraPosition(target: LatLng(30.0455, 31.2360), zoom: 12.4746); late GoogleMapController? gmcontroller; bool loading = true; double radius = 1500; late AnimationController animationController; late ValueNotifier<double> animationValueNotifier; Set<Circle> circles = {}; @override void initState() { super.initState(); animationController = AnimationController( vsync: this, duration: const Duration(milliseconds: 800), )..repeat(); // 用ValueNotifier管理动画值,仅更新需要变化的部分 animationValueNotifier = ValueNotifier(0.0); animationController.addListener(() { animationValueNotifier.value = animationController.value; }); _delay(); } void _delay() { Future.delayed(const Duration(milliseconds: 500), () => setState(() => loading = false)); } @override void dispose() { animationController.dispose(); animationValueNotifier.dispose(); gmcontroller?.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( body: !loading ? Consumer<StationController>( builder: (context, value, child) { return GoogleMap( initialCameraPosition: ciaro, zoomControlsEnabled: true, // 仅在动画值变化时更新Circles circles: ValueListenableBuilder<double>( valueListenable: animationValueNotifier, builder: (context, animValue, _) { return value.stations.map<Circle>((e) { final circleId = CircleId(e.name!); // 查找已存在的Circle,复用并更新属性 final existingCircle = circles.firstWhere( (c) => c.circleId == circleId, orElse: () => Circle( circleId: circleId, center: e.location!, strokeColor: Colors.transparent, strokeWidth: 1, visible: true, ), ); return existingCircle.copyWith( radiusParam: radius * animValue, fillColorParam: kPrimaryColor.withOpacity((animValue - 1.0).abs()), ); }).toSet()..forEach((circle) => circles.add(circle)); }, ), markers: value.stations.map<Marker>((element) => Marker( markerId: MarkerId(element.name!), position: element.location!, consumeTapEvents: true, icon: element.selected ? element.iconNotSelected : element.iconSelected, onTap: () => value.addStation(element.name), )).toSet(), onMapCreated: (GoogleMapController controller) { gmcontroller = controller; gmcontroller!.setMapStyle(jsonEncode(mapStyle)); }, ); }, ) : const Center( child: CircularProgressIndicator(color: kPrimaryColor, strokeWidth: 2.0), ), ); } }
额外优化建议
- 若不需要无限循环动画,移除
animationController.repeat(),改为按需触发动画。 - 减少动画帧频率:适当延长动画时长,降低每秒钟的重建次数。
- 对Marker也做类似复用优化:如果Marker状态不频繁变化,避免每次重建都重新生成。
关于flutter_animarker:该库主要针对Marker的路径移动动画做优化,对于Circle的缩放场景适配性有限,仍需通过上述局部更新逻辑优化性能。
内容的提问来源于stack exchange,提问作者Muhammad Muddassar
相关产品推荐
相关产品推荐

