我想在使用FutureBuilder构建的listview的底部隐藏浮动的actionbutton,我在listview中使用了ScrollerController来检测用户何时向前滚动,并且如果用户滚动前叉然后调用setState则隐藏actionbutton,但是无论何时我调用FutureBuilder future将重复运行,这是一个异步sqlite get查询。我使用了AsynMemoizer,但这也无济于事。这是我的代码示例:
class _MyHomePageState extends State<MyHomePage> {
bool show = true;
ScrollController _controller = ScrollController();
final AsyncMemoizer _memoizer = AsyncMemoizer();
@override
void initState() {
super.initState();
_controller.addListener(listener);
}
void listener() {
if (_controller.position.userScrollDirection == ScrollDirection.forward) {
show = true;
} else if (_controller.position.userScrollDirection ==
ScrollDirection.reverse) {
show = false;
}
setState(() {});
}
int _counter = 0;
int id = 0;
Future<List<Dog>> _getDogs() async {
// return this._memoizer.(() async {
// return await getDogs();
// });
}
void _insertDog() async {
id++;
var fido = Dog(id: id, name: "fido$id", age: id * 3);
await insertDog(fido);
setState(() {});
}
void _updateDog(Dog fido) async {
fido = Dog(
id: fido.id,
name: fido.name,
age: fido.age + 7,
);
await updateDog(fido);
setState(() {});
}
void _deleteDog(int id) async {
await deleteDog(id);
setState(() {});
}
@override
void dispose() {
_controller.removeListener(listener);
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Sqflite Demo"),
),
body: Container(
child: FutureBuilder(
future: getDogs(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return ListView.builder(
controller: _controller,
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(snapshot.data[index].name),
subtitle: Text("Age: ${snapshot.data[index].age}"),
onTap: () => _updateDog(snapshot.data[index]),
onLongPress: () => _deleteDog(snapshot.data[index].id),
);
},
);
} else {
return Container(
child: Center(
child: Text("Loading..."),
));
}
},
),
),
floatingActionButton: Visibility(
visible: show,
child: Stack(
children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 30),
child: Align(
alignment: Alignment.bottomLeft,
child: FloatingActionButton(
onPressed: () {
setState(() {});
},
child: Icon(Icons.refresh),
),
),
),
Align(
alignment: Alignment.bottomRight,
child: FloatingActionButton(
onPressed: _insertDog,
tooltip: 'Increment',
child: Icon(Icons.add),
),
),
],
),
));
}
}
答案 0 :(得分:0)
在initState中调用getDogs()
,将Future实例保存在State中。然后在FutureBuilder中使用该Future变量。这样,如果已经解决,它将不会在每个构建中得到调用。
答案 1 :(得分:0)
感谢Martyns提供一种快速,智能的解决方案,一点是,每当我要更新listview时,都必须将getDogs()重新分配给将来的状态实例变量,以强制FutureBuilder运行。这是正确的源代码:
class _MyHomePageState extends State<MyHomePage> {
bool show = true;
ScrollController _controller = ScrollController();
Future<List<Dog>> future;
@override
void initState() {
super.initState();
future = getDogs();
_controller.addListener(listener);
}
void listener() {
if (_controller.position.userScrollDirection == ScrollDirection.forward) {
show = true;
} else if (_controller.position.userScrollDirection ==
ScrollDirection.reverse) {
show = false;
}
setState(() {});
}
int _counter = 0;
int id = 0;
void _insertDog() async {
id++;
var fido = Dog(id: id, name: "fido$id", age: id * 3);
await insertDog(fido);
setState(() {future = getDogs();});
}
void _updateDog(Dog fido) async {
fido = Dog(
id: fido.id,
name: fido.name,
age: fido.age + 7,
);
await updateDog(fido);
setState(() {future = getDogs();});
}
void _deleteDog(int id) async {
await deleteDog(id);
setState(() {future = getDogs();});
}
@override
void dispose() {
_controller.removeListener(listener);
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Sqflite Demo"),
),
body: Container(
child: FutureBuilder(
future: future,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return ListView.builder(
controller: _controller,
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(snapshot.data[index].name),
subtitle: Text("Age: ${snapshot.data[index].age}"),
onTap: () => _updateDog(snapshot.data[index]),
onLongPress: () => _deleteDog(snapshot.data[index].id),
);
},
);
} else {
return Container(
child: Center(
child: Text("Loading..."),
));
}
},
),
),
floatingActionButton: Visibility(
visible: show,
child: Stack(
children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 30),
child: Align(
alignment: Alignment.bottomLeft,
child: FloatingActionButton(
onPressed: () {
setState(() {future = getDogs();});
},
child: Icon(Icons.refresh),
),
),
),
Align(
alignment: Alignment.bottomRight,
child: FloatingActionButton(
onPressed: _insertDog,
tooltip: 'Increment',
child: Icon(Icons.add),
),
),
],
),
));
}