我正在写一个扑扑的App。 我当前的问题是我想显示一个按钮列表,用于从网站打开不同的pdf文件。该按钮列表是使用网络抓取创建的。该函数返回字符串的将来列表。从该字符串列表中,将创建一个将来的材料按钮列表。
由于网络抓取需要很长时间,因此在按钮列表尚未准备就绪时,应显示一个LoadingDialog。然后,应显示按钮列表。
使用我当前的代码,按钮列表被创建了两次。第一次创建它,并显示一个LoadingDialog。然后隐藏LoadingDialog,屏幕为白色,再次创建按钮列表,当按钮列表准备就绪时,它将显示在屏幕上。
如何防止列表重新形成?
这是我的代码:
class PlanScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: new AdvancedAppBar(context: context),
body: PlanForm(),
);
}
}
class PlanForm extends StatefulWidget {
@override
PlanState createState() {
return PlanState();
}
}
class PlanState extends State<PlanForm> {
String pathPDF;
List<MaterialButton> _buttonsList = [];
bool _listVariable = false;
Future<List<String>> doed()async {
// doed returns a Future<List<String>> with file names
}
@override
void initState() {
createFileOfPdfUrl("File-URL").then((f){setState((){pathPDF = f.path;});});
super.initState();
}
Future<List<Widget>> _buildButtonsWithNames() async{
List<String> list = [];
await doed().then((value){list = value;});
int length = list.length;
print("Länge der List " + length.toString());
_buttonsList = [];
for (int i = 0; i < length; i++) {
List<String> linkSplitted = list[0].split("/");
String buttonName = linkSplitted[linkSplitted.length-1];
_buttonsList
.add(new MaterialButton(
height: 40.0,
minWidth: 300.0,
color: phwtblue,
textColor: Colors.white,
child: new Text(buttonName, textScaleFactor: 2.0,),
onPressed: () {
bool hi = true;
if(buttonName.contains(".html"))
{
Navigator.push(context, new MaterialPageRoute(builder: (context) => new MyApp2()),
);
} else if (buttonName.contains(".pdf"))
{
Navigator.push(context, new MaterialPageRoute(builder: (context) => new PDFView(pathPDF)),
);
}
}
));
print(list.length);
list.removeAt(0);
}
print(_buttonsList.length);
return _buttonsList;
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<List<Widget>>(
future: _buildButtonsWithNames().then((list){_buttonsList = list;}),
builder: (BuildContext context, AsyncSnapshot<List<Widget>> snapshot) {
while(snapshot.connectionState == ConnectionState.waiting){
showLoadingDialog();
return Column();
}
if(snapshot.connectionState == ConnectionState.done){
hideLoadingDialog();
_listVariable = false;
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints viewportConstraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: viewportConstraints.maxHeight,
),
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: _buttonsList,
)
)
)
);
}
);
},
)
);
}
}
答案 0 :(得分:0)
原因
https://github.com/flutter/flutter/issues/11426#issuecomment-414047398
每次发出重新构建时,都会调用FutureBuilder状态的didUpdateWidget。此函数检查旧的Future对象是否与新的对象不同,如果有,则重新启动FutureBuilder。为了克服这个问题,我们可以在build函数之外的其他地方调用Future。
解决方案
https://github.com/flutter/flutter/issues/11426#issuecomment-414047398
代码段
Future<List<Widget>> Function() _future;
...
@override
void initState() {
//createFileOfPdfUrl("File-URL").then((f){setState((){pathPDF = f.path;});});
super.initState();
_future = _buildButtonsWithNames;
}
...
FutureBuilder<List<Widget>>(
future: _future().then((list) {
_buttonsList = list;
}),
完整的测试代码
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: PlanScreen(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
class PlanScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("test"),
),
body: PlanForm(),
);
}
}
class PlanForm extends StatefulWidget {
@override
PlanState createState() {
return PlanState();
}
}
class PlanState extends State<PlanForm> {
String pathPDF;
List<MaterialButton> _buttonsList = [];
bool _listVariable = false;
Future<List<String>> doed() async {
// doed returns a Future<List<String>> with file names
await Future.delayed(const Duration(seconds: 3), () {});
return ["123", "456", "abc", "def"];
/*setState(() {
return ["123", "456", "abc", "def"];
});*/
}
Future<List<Widget>> Function() _future;
@override
void initState() {
//createFileOfPdfUrl("File-URL").then((f){setState((){pathPDF = f.path;});});
super.initState();
_future = _buildButtonsWithNames;
}
Future<List<Widget>> _buildButtonsWithNames() async {
print("_buildButtonsWithNames()");
List<String> list = [];
await doed().then((value) {
list = value;
});
int length = list.length;
print("Länge der List " + length.toString());
_buttonsList = [];
for (int i = 0; i < length; i++) {
List<String> linkSplitted = list[0].split("/");
String buttonName = linkSplitted[linkSplitted.length - 1];
_buttonsList.add(new MaterialButton(
height: 40.0,
minWidth: 300.0,
color: Colors.blue,
textColor: Colors.white,
child: new Text(
buttonName,
textScaleFactor: 2.0,
),
onPressed: () {
bool hi = true;
if (buttonName.contains(".html")) {
//Navigator.push(context, new MaterialPageRoute(builder: (context) => new MyApp2()),
//);
} else if (buttonName.contains(".pdf")) {
//Navigator.push(context, new MaterialPageRoute(builder: (context) => new PDFView(pathPDF)),
//);
}
}));
print(list.length);
list.removeAt(0);
}
print(_buttonsList.length);
return _buttonsList;
}
@override
Widget build(BuildContext context) {
print("build");
return Scaffold(
body: FutureBuilder<List<Widget>>(
future: _future().then((list) {
_buttonsList = list;
}),
builder:
(BuildContext context, AsyncSnapshot<List<Widget>> snapshot) {
while (snapshot.connectionState == ConnectionState.waiting) {
//showLoadingDialog();
print("show loading");
return Column();
}
if (snapshot.connectionState == ConnectionState.done) {
//hideLoadingDialog();
print("hide loading");
_listVariable = false;
return LayoutBuilder(builder:
(BuildContext context, BoxConstraints viewportConstraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: viewportConstraints.maxHeight,
),
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: _buttonsList,
))));
});
}
}));
}
}