我想要实现的目标:仅当网页以状态 200 响应时才显示 FAB。
以下是我的代码的必要部分,我使用异步方法检查网页:
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
late Future<Widget> futureWidget;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
void initState() {
super.initState();
futureWidget = _getFAB();
}
Future<Widget> _getFAB() async {
final response = await http
.get(Uri.parse('https://jsonplaceholder.typicode.com/albums/1'));
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// return something to create FAB
return const Text('something');
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load url');
}
}
如果快照有数据,我可以使用以下 FutureBuilder 获得结果:
body: Center(
child: FutureBuilder<Widget>(
future: futureWidget,
builder: (context, snapshot) {
if (snapshot.hasData) {
return FloatingActionButton(
backgroundColor: Colors.deepOrange[800],
child: Icon(Icons.add_shopping_cart),
onPressed:
null); // navigate to webview, will be created later
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
// By default, show a loading spinner.
return const CircularProgressIndicator();
},
)
我的问题是我想在这里使用它,作为一个 floatingActionButton 小部件:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
[further coding...]
),
body: // Indexed Stack to keep data
IndexedStack(
index: _selectedIndex,
children: _pages,
),
floatingActionButton: _getFAB(),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>
[further coding...]
但在这种情况下,Flutter 抛出错误参数类型“Future”不能分配给参数类型“Widget?”。
当然,因为我没有以这种方式使用 FutureBuilder。但是当我在上面的编码中使用 FutureBuilder 时, Flutter 期望进一步的位置参数,例如 column 。这以完全不同的视图结束,因为 FAB 不再放置在典型 FAB 位置的索引堆栈上。
我已经搜索了几个小时来寻找类似的问题,但一无所获。也许我的代码太复杂了,但 Flutter 对我来说还是新的。如果有人可以帮助我,那就太好了:)
回答1
您可以使用 just _getFAB() 方法来执行此操作。您不能将 _getFab() 方法的返回 value 分配给任何小部件,因为它具有返回类型 Future。而且,当您尝试从 FutureBuilder 返回 FAB 时,它将在 Scaffold 主体内返回 FAB。
因此,我建议您从 _getFAB() 方法中获取数据并将这些数据分配给类级别变量。它可以是 bool、map 或模型类等。您必须在小部件树中放置条件语句以填充数据获取之前和数据获取之后的状态。然后调用 setState((){}) 它将使用新数据重建小部件树。下面是一个简单的例子。
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class FabFuture extends StatefulWidget {
const FabFuture({Key? key}) : super(key: key);
@override
State<FabFuture> createState() => _FabFutureState();
}
class _FabFutureState extends State<FabFuture> {
bool isDataLoaded = false;
@override
void initState() {
super.initState();
_getFAB();
}
Future<void> _getFAB() async {
final response = await http
.get(Uri.parse('https://jsonplaceholder.typicode.com/albums/1'));
if (response.statusCode == 200) {
isDataLoaded = true;
setState(() {});
} else {
isDataLoaded = false;
//TODO: handle error
setState(() {});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: const Center(
child: Text('Implemet body here'),
),
floatingActionButton: isDataLoaded
? FloatingActionButton(
backgroundColor: Colors.deepOrange[800],
child: const Icon(Icons.add_shopping_cart),
onPressed: null)
: const SizedBox(),
);
}
}
在这里,我使用了一个简单的 bool value 来确定是否应该显示 FAB。 FAB 仅在成功获取数据后才会显示。在实践了这些方法并且您对它们充满信心之后,我想建议学习状态管理解决方案来处理这些类型的工作。