Flutter世界时钟项目Navigator.pop报context未定义错误求助
我正在跟着教程开发Flutter「世界时钟」项目,作为新手碰到了一个错误:在Choose页面使用Navigator.pop时提示Undefined name 'context'。
项目流程是:Loading页面通过Navigator.pushReplacementNamed初始化Home页面;我想在Choose页面用ListView.builder创建新的WorldTime实例,再通过Navigator.pop把数据返回上一页,但报错了。
相关代码
Choose Page
import 'package:flutter/material.dart'; import 'package:world_time/services/world_time.dart'; class ChooseLocation extends StatefulWidget { const ChooseLocation({Key? key}) : super(key: key); @override State<ChooseLocation> createState() => _ChooseLocationState(); } List<WorldTime> locations = [ WorldTime('Lagos', 'time', 'nigeria.png', 'Africa/Lagos', true), WorldTime('Islamabad', 'time', 'pakistan.png', 'Asia/Islamabad', true), WorldTime('Lund', 'time', 'sweden.png', 'Europe/Lund', true), WorldTime('Birmingham', 'time', 'uk.png', 'Europe/Birmingham', true), WorldTime('London', 'time', 'uk.png' , 'Europe/London', true), WorldTime('Athens', 'time', 'greece.png', 'Europe/Berlin', true), WorldTime('Cairo', 'time', 'egypt.png', 'Africa/Cairo', true), WorldTime('Nairobi', 'time', 'kenya.png', 'Africa/Nairobi', true), WorldTime('Chicago', 'time', 'usa.png', 'America/Chicago', true), WorldTime('New York', 'time', 'usa.png', 'America/New_York', true), WorldTime('Seoul', 'time', 'south_korea.png', 'Asia/Seoul', true), WorldTime('Jakarta', 'time', 'indonesia.png', 'Asia/Jakarta', true), ]; void updateTime(index) async { WorldTime instance = locations[index]; await instance.getTime(); // 错误发生在这一行:Undefined name 'context' Navigator.pop(context, { 'location': instance.location, 'flag': instance.flag, 'time': instance.time, 'isDayTime': instance.isDayTime}); } class _ChooseLocationState extends State<ChooseLocation> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Colors.blue[800], title: const Text('Choose A Location'), centerTitle: true, elevation: 0, ), body: ListView.builder(itemCount:locations.length, itemBuilder: (context, index){ return Padding( padding: const EdgeInsets.symmetric(vertical: 1.0, horizontal: 4.0), child: Card( child: ListTile( onTap: (){ updateTime(index); }, title: Text(locations[index].location), leading: CircleAvatar( backgroundImage: AssetImage('assets/${locations[index].flag}'), ), ), ), ); } ), ); } }
Loading Page
import 'package:flutter/material.dart'; import 'package:world_time/services/world_time.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart'; class Loading extends StatefulWidget { const Loading({Key? key}) : super(key: key); @override State<Loading> createState() => _LoadingState(); } class _LoadingState extends State<Loading> { void setupWorldTime() async { WorldTime instance = WorldTime('Berlin', 'time', 'germany.png', 'Europe/Berlin', true); await instance.getTime(); Navigator.pushReplacementNamed(context,'/home', arguments: { 'location': instance.location, 'flag': instance.flag, 'time': instance.time, 'isDayTime': instance.isDayTime }); } @override void initState(){ super.initState(); setupWorldTime(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.lightBlue, body:Center( child: SpinKitFadingCircle( itemBuilder: (BuildContext context, int index) { return DecoratedBox( decoration: BoxDecoration( color: index.isEven ? Colors.white : Colors.lightBlue, ), ); }, ), ), ); } }
Home Page
class Home extends StatefulWidget { const Home({Key? key}) : super(key: key); @override State<Home> createState() => _HomeState(); } class _HomeState extends State<Home> { Map data = {}; @override Widget build(BuildContext context) { data = data.isNotEmpty ? data : ModalRoute.of(context)?.settings.arguments as Map<dynamic,dynamic>; print(data); String bgImage = (data?['isDayTime'] ?? false) ?'day.png' : 'night.png'; Color bgColor = (data?['isDayTime'] ?? false) ? Colors.lightBlue : Colors.blue; return Scaffold( backgroundColor: bgColor, body: Container( decoration: BoxDecoration( image: DecorationImage( image: AssetImage('assets/$bgImage'), fit:BoxFit.cover, ), ), child: Padding( padding: const EdgeInsets.fromLTRB(0,120,0,0), child: SafeArea( child: Column( children: [ TextButton.icon(onPressed: ()async { dynamic result = await Navigator.pushNamed(context, '/location'); setState(() { data = { 'time': result['time'], 'location': result['location'], 'isDayTime': result['isDayTime'], 'flag': result['flag'] }; }); }, icon: const Icon(Icons.edit_location), label: const Text('Edit Location'), style: TextButton.styleFrom( foregroundColor: Colors.grey[300], ), ), SizedBox(height: 20.0), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(data['location'], style: TextStyle(fontSize: 28, letterSpacing: 2, color: Colors.white), ), ], ), SizedBox(height: 20), Text(data['time'], style: TextStyle(fontSize: 66, color: Colors.white), ), ], ), ), ), ), ); } }
问题原因
updateTime是全局函数,无法访问State类中的context对象。Flutter的context仅能在Widget树的上下文范围内使用,全局函数不在这个有效范围内。
解决方法
方法1:将updateTime移到State类内部
把updateTime改为_ChooseLocationState的类方法,直接访问类内的context:
class _ChooseLocationState extends State<ChooseLocation> { // 移到State类内部 void updateTime(int index) async { WorldTime instance = locations[index]; await instance.getTime(); Navigator.pop(context, { 'location': instance.location, 'flag': instance.flag, 'time': instance.time, 'isDayTime': instance.isDayTime }); } @override Widget build(BuildContext context) { // 其余代码不变 } }
同时删除原来的全局updateTime函数。
方法2:给全局updateTime传入context参数
如果要保留全局函数,调用时把itemBuilder中的context传进去:
// 修改全局函数,添加context参数 void updateTime(BuildContext context, int index) async { WorldTime instance = locations[index]; await instance.getTime(); Navigator.pop(context, { 'location': instance.location, 'flag': instance.flag, 'time': instance.time, 'isDayTime': instance.isDayTime }); } // 在ListTile的onTap中传入context onTap: (){ updateTime(context, index); },
推荐方法1,它更符合Flutter代码组织规范,避免全局函数带来的潜在问题。
内容的提问来源于stack exchange,提问作者HungerMadra
相关产品推荐
相关产品推荐

