如何在Flutter的AppBar标题中显示FutureBuilder快照数据中的Recipe对象名称
如何在Flutter的AppBar标题中显示FutureBuilder快照数据中的Recipe对象名称
我明白你现在的困扰——AppBar是Scaffold的顶层组件,没法直接拿到body里FutureBuilder的快照数据对吧?别担心,这里有两个简单可行的方案帮你解决这个问题:
方案一:把整个Scaffold嵌套进FutureBuilder
这个方法的思路很直接:既然AppBar需要用到异步加载的数据,那我们就把整个Scaffold都放到FutureBuilder的builder方法里,这样当数据加载完成后,AppBar和body就能共享同一个快照数据了,还能统一处理加载、错误状态。
修改后的完整代码如下:
@override void initState() { super.initState(); futureRecipe = RecipeDataService().getRecipe(widget.id); } @override Widget build(BuildContext context) { return FutureBuilder<Recipe>( future: futureRecipe, builder: (context, snapshot) { // 加载中状态:显示带加载提示的AppBar和进度圈 if (snapshot.connectionState == ConnectionState.waiting) { return Scaffold( extendBodyBehindAppBar: true, appBar: AppBar( centerTitle: true, title: Text("加载中..."), ), body: const Center(child: CircularProgressIndicator()), ); } // 错误状态:显示错误提示的AppBar和错误文本 else if (snapshot.hasError) { return Scaffold( extendBodyBehindAppBar: true, appBar: AppBar( centerTitle: true, title: Text("加载失败"), ), body: Center(child: Text('${snapshot.error}')), ); } // 数据加载完成:正常显示AppBar和内容 else if (snapshot.hasData) { Recipe recipe = snapshot.data!; return Scaffold( extendBodyBehindAppBar: true, appBar: AppBar( centerTitle: true, title: Text(recipe.name), // 这里直接用Recipe的名称 ), body: Container( child: Column( children: [ Text( "${recipe.cuisine}, ${recipe.difficulty}", style: TextStyle(fontSize: 20, fontWeight: FontWeight.w300), ), Text( recipe.name, style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold), ), // 其他组件... ], ), ), ); } // 兜底的加载状态 return const Scaffold( body: Center(child: CircularProgressIndicator()), ); }, ); }
方案二:用StatefulWidget的状态变量缓存加载后的Recipe
如果不想重构整个Widget的结构,你可以在State类里加一个状态变量,专门缓存加载完成的Recipe对象,等异步请求完成后更新状态,这样AppBar就能直接读取这个状态变量的值了。
修改后的代码示例:
// 在State类里新增状态变量 Recipe? _loadedRecipe; String? _loadError; @override void initState() { super.initState(); // 发起请求并缓存结果 RecipeDataService().getRecipe(widget.id) .then((recipe) { setState(() { _loadedRecipe = recipe; }); }) .catchError((error) { setState(() { _loadError = error.toString(); }); }); } @override Widget build(BuildContext context) { return Scaffold( extendBodyBehindAppBar: true, appBar: AppBar( centerTitle: true, // 根据状态显示不同的标题 title: Text( _loadedRecipe != null ? _loadedRecipe!.name : _loadError != null ? "加载失败" : "加载中...", ), ), body: Container( child: _loadedRecipe != null ? Column( children: [ Text( "${_loadedRecipe!.cuisine}, ${_loadedRecipe!.difficulty}", style: TextStyle(fontSize: 20, fontWeight: FontWeight.w300), ), Text( _loadedRecipe!.name, style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold), ), // 其他组件... ], ) : _loadError != null ? Center(child: Text(_loadError!)) : Center(child: CircularProgressIndicator()), ), ); }
小提示
- 两种方案都要记得处理加载中和加载错误的状态,别让用户看到空白或者异常的AppBar标题
- 方案一更适合数据加载后整个页面结构都依赖该数据的场景,方案二更灵活,适合不想大改原有代码的情况
内容来源于stack exchange
相关产品推荐
相关产品推荐

