Flutter Hooks 与 flutter_map_animations 冲突:第二次地图动画报错的解决方案

Flutter Hooks 与 flutter_map_animations 冲突:第二次地图动画报错的解决方案

在 HookWidget 中使用 flutter_map_animations 时,如果把 useSingleTickerProvider() 传给 AnimatedMapController:

dart 复制代码
final tickerProvider = useSingleTickerProvider();

final animatedMapController = useMemoized(
  () => AnimatedMapController(
    vsync: tickerProvider,
  ),
);

第一次地图动画可以正常执行。

第二次执行动画时,会抛出:

css 复制代码
A SingleTickerProviderStateMixin can only be used as a TickerProvider once.

If a State is used for multiple AnimationController objects, or if it is
passed to other objects and those objects might use it more than one time
in total, then instead of mixing in a SingleTickerProviderStateMixin,
use a regular TickerProviderStateMixin.

原因是 useSingleTickerProvider() 只能创建一个 Ticker,而 AnimatedMapController 在多次地图动画中可能创建多个 AnimationController。

flutter_hooks 已经有一个增加 useMultiTickerProvider() 的 PR:

github.com/rrousselGit...

但该功能还没有进入正式版本,因此可以先在项目中加入一个自定义实现:

dart 复制代码
import 'package:flutter/foundation.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_hooks/flutter_hooks.dart';

TickerProvider useMultiTickerProvider({List<Object?>? keys}) {
  return use(
    keys != null
        ? _MultiTickerProviderHook(keys)
        : const _MultiTickerProviderHook(),
  );
}

class _MultiTickerProviderHook extends Hook<TickerProvider> {
  const _MultiTickerProviderHook([List<Object?>? keys])
      : super(keys: keys);

  @override
  _MultiTickerProviderHookState createState() =>
      _MultiTickerProviderHookState();
}

class _MultiTickerProviderHookState
    extends HookState<TickerProvider, _MultiTickerProviderHook>
    implements TickerProvider {
  final Set<Ticker> _tickers = <Ticker>{};

  ValueListenable<bool>? _tickerModeNotifier;

  @override
  Ticker createTicker(TickerCallback onTick) {
    final ticker = Ticker(
      onTick,
      debugLabel: 'created by $context (multi)',
    );

    _updateTickerModeNotifier();

    _tickers.add(ticker);

    _updateTickers();

    return ticker;
  }

  @override
  void dispose() {
    assert(() {
      for (final ticker in _tickers) {
        if (ticker.isActive) {
          throw FlutterError(
            'useMultiTickerProvider created Ticker(s), but at the time '
            'dispose() was called on the Hook, at least one of those Tickers '
            'was still active.',
          );
        }
      }

      return true;
    }(), '');

    _tickerModeNotifier?.removeListener(_updateTickers);
    _tickerModeNotifier = null;

    _tickers.clear();

    super.dispose();
  }

  @override
  TickerProvider build(BuildContext context) {
    _updateTickerModeNotifier();
    _updateTickers();

    return this;
  }

  void _updateTickers() {
    if (_tickers.isEmpty) {
      return;
    }

    final muted =
        !(_tickerModeNotifier?.value ?? TickerMode.of(context));

    for (final ticker in _tickers) {
      ticker.muted = muted;
    }
  }

  void _updateTickerModeNotifier() {
    final newNotifier = TickerMode.getNotifier(context);

    if (newNotifier == _tickerModeNotifier) {
      return;
    }

    _tickerModeNotifier?.removeListener(_updateTickers);

    newNotifier.addListener(_updateTickers);

    _tickerModeNotifier = newNotifier;
  }

  @override
  String get debugLabel => 'useMultiTickerProvider';

  @override
  bool get debugSkipValue => true;
}

然后把:

dart 复制代码
final tickerProvider = useSingleTickerProvider();

改成:

dart 复制代码
final tickerProvider = useMultiTickerProvider();

final animatedMapController = useMemoized(
  () => AnimatedMapController(
    vsync: tickerProvider,
  ),
);

将 useSingleTickerProvider() 替换为 useMultiTickerProvider(),避免 AnimatedMapController 第二次创建动画时触发单 Ticker 限制。

相关推荐
程序员老刘1 小时前
Flutter你看看人家RN
flutter·react native·ai编程
大龄秃头程序员7 小时前
【Flutter Bloc 从 0 到 1】用最少代码跑通 Bloc
flutter
m0_738185828 小时前
Flutter 鸿蒙化实战:sqflite 适配 OpenHarmony,本地 SQLite 数据库
flutter·华为·harmonyos·鸿蒙
梦曦i9 小时前
uni-app、uni-app x 与 Flutter 深度对比:2026年跨平台开发框架选型指南
flutter·uni-app·uni-app x
恋猫de小郭10 小时前
Flitz ,一个把 Flutter 玩成热插拔 Preview 的有趣项目,不错的思路
android·前端·flutter
FungLeo10 小时前
成为全栈·Flutter App 篇·Refresh Token 旋转与并发 401:安全存储与会话代次
flutter·jwt·移动安全·身份认证·token刷新·成为全栈
m0_7381858211 小时前
Flutter 鸿蒙化实战:simple_circular_progress_bar 适配 OpenHarmony,环形进度条
flutter·华为·harmonyos·鸿蒙
大龄秃头程序员1 天前
Riverpod 深度解析:从响应式本质到最小可运行闭环
flutter
曹小强wxx1 天前
让 AI 写代码不“翻车”:用 Claude Code + Codex 给 Flutter 项目搭一套工程规范
flutter·ai编程·claude