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

Flutter技术问题:如何在ChangeNotifier类中传递Context

解决方案

方案一:将点击事件移至UI层处理(推荐)

状态管理类的核心职责是维护数据,不应直接处理UI交互逻辑。正确的做法是在地图组件中监听Circle的点击事件,在UI层调用BottomSheet——因为UI层可以直接获取BuildContext。

修改步骤:

  1. 更新GoogleMapModel:移除Circle的onTap回调,只保留数据逻辑:
void EarthQuakeItems() async {
  _circleItems.clear();
  _markerItems.clear();
  _sheetItems.clear();
  try {
    List<EarthQuake> value = await client.getEarthQuakeRecent();
    if (value.isNotEmpty) {
      for (int i = 0; i < value.length; i++) {
        _circleItems.add(Circle(
          circleId: CircleId(value[i].id.toString()),
          center: LatLng(value[i].latitude, value[i].longitude),
          fillColor: Colors.blue.withOpacity(0.5),
          radius: value[i].magnitude * 10000,
          strokeColor: Colors.blueAccent,
          strokeWidth: 1,
          consumeTapEvents: true, // 保留此属性确保Circle优先接收点击
        ));
      }
    }
  } catch (error) {
    // 错误处理逻辑
  }
  notifyListeners();
}
  1. 在Google_Map组件中监听点击:
    假设你的Google_Map是基于官方GoogleMap封装的,添加onCircleTap回调:
class Google_Map extends StatelessWidget {
  final List<Circle> circleItems;
  final List<ClusterData> markerItems;
  final GoogleMapMode mode;

  const Google_Map({
    super.key,
    required this.circleItems,
    required this.markerItems,
    required this.mode,
  });

  @override
  Widget build(BuildContext context) {
    return GoogleMap(
      circles: Set<Circle>.from(circleItems),
      markers: // 你的Marker处理逻辑
      onCircleTap: (CircleId circleId) {
        final earthQuakeId = circleId.value;
        BottomSheets.showItemBottomSheet(context, earthQuakeId);
      },
      // 其他地图配置项
    );
  }
}

方案二:在Model中维护点击回调函数

如果需要在Model中触发点击逻辑,可以在GoogleMapModel中定义一个回调字段,由UI层传入带Context的实现。

修改步骤:

  1. 更新GoogleMapModel:添加回调字段并在Circle点击时调用:
class GoogleMapModel with ChangeNotifier {
  // 新增点击回调字段
  Function(String)? onCircleTap;

  // ... 现有代码

  void EarthQuakeItems() async {
    _circleItems.clear();
    _markerItems.clear();
    _sheetItems.clear();
    try {
      List<EarthQuake> value = await client.getEarthQuakeRecent();
      if (value.isNotEmpty) {
        for (int i = 0; i < value.length; i++) {
          _circleItems.add(Circle(
            circleId: CircleId(value[i].id.toString()),
            center: LatLng(value[i].latitude, value[i].longitude),
            fillColor: Colors.blue.withOpacity(0.5),
            radius: value[i].magnitude * 10000,
            strokeColor: Colors.blueAccent,
            strokeWidth: 1,
            onTap: () {
              onCircleTap?.call(value[i].id.toString());
            },
            consumeTapEvents: true,
          ));
        }
      }
    } catch (error) {
      // 错误处理逻辑
    }
    notifyListeners();
  }
}
  1. 在UI层绑定回调:在EQ_Info的initState中设置回调:
class _EQ_InfoState extends State<EQ_Info> {
  @override
  void initState() {
    super.initState();
    final mapModel = context.read<GoogleMapModel>();
    mapModel.onCircleTap = (earthQuakeId) {
      BottomSheets.showItemBottomSheet(context, earthQuakeId);
    };
  }

  // ... 现有代码
}

方案三:正确使用GlobalKey获取Context

若坚持使用GlobalKey,需确保其正确关联到MaterialApp的Navigator:

修改步骤:

  1. 定义全局GlobalKey:在main.dart中声明:
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  // ... 其他初始化逻辑

  runApp(MaterialApp(
    navigatorKey: navigatorKey, // 关联key到Navigator
    home: RootScreen(),
  ));
}
  1. 在GoogleMapModel中使用GlobalKey:
// 导入main.dart中的navigatorKey
import 'main.dart';

class GoogleMapModel with ChangeNotifier {
  // ... 现有代码

  void EarthQuakeItems() async {
    // ... 循环创建Circle
    onTap: () {
      final context = navigatorKey.currentState?.context;
      if (context != null) {
        BottomSheets.showItemBottomSheet(context, value[i].id.toString());
      }
    },
    // ... 其他Circle属性
  }
}

其他显示容器的实现方式

如果不想使用showBottomSheet,还可以通过以下方式实现点击Circle显示容器:

1. 自定义可动画底部面板(Stack + AnimatedPositioned)

在EQ_Info的Stack中添加一个可动画的容器,通过Model维护选中的地震ID,控制容器的显示/隐藏:

// 在GoogleMapModel中新增状态字段
String? _selectedEarthQuakeId;
String? get selectedEarthQuakeId => _selectedEarthQuakeId;

void setSelectedEarthQuakeId(String? id) {
  _selectedEarthQuakeId = id;
  notifyListeners();
}

// 在EQ_Info的Stack中添加:
AnimatedPositioned(
  duration: const Duration(milliseconds: 300),
  bottom: context.watch<GoogleMapModel>().selectedEarthQuakeId != null ? 0 : -300,
  left: 0,
  right: 0,
  height: 300,
  child: Container(
    color: Colors.white,
    padding: const EdgeInsets.all(16),
    child: // 渲染选中的地震信息
  ),
)

// 在地图的onCircleTap中触发状态变更:
onCircleTap: (CircleId circleId) {
  context.read<GoogleMapModel>().setSelectedEarthQuakeId(circleId.value);
}

2. 使用DraggableScrollableSheet

通过Model控制可拖拽底部面板的显示状态:

// 在GoogleMapModel中新增状态字段
bool _showSheet = false;
bool get showSheet => _showSheet;
String? _selectedEarthQuakeId;
String? get selectedEarthQuakeId => _selectedEarthQuakeId;

void toggleSheet(String? id) {
  _selectedEarthQuakeId = id;
  _showSheet = id != null;
  notifyListeners();
}

// 在EQ_Info的Stack中添加:
if (context.watch<GoogleMapModel>().showSheet) {
  DraggableScrollableSheet(
    initialChildSize: 0.3,
    maxChildSize: 0.8,
    minChildSize: 0.3,
    builder: (context, scrollController) {
      return Container(
        color: Colors.white,
        child: ListView(
          controller: scrollController,
          children: // 渲染地震信息列表
        ),
      );
    },
  );
}

内容的提问来源于stack exchange,提问作者jungeyonoh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 12:32:30