子窗口小部件的Flutter setState无需重建父窗口 [英] Flutter setState of child widget without rebuilding parent
问题描述
我有一个包含 listView
和 floatingActionButton
的父级,我想在用户开始滚动时隐藏 floatingActionButton
要在父窗口小部件中执行此操作,但这需要每次都重新构建列表.
I have a parent that contain a listView
and a floatingActionButton
i would like to hide the floatingActionButton
when the user starts scrolling i have managed to do this within the parent widget but this requires the list to be rebuilt each time.
我将 floatingActionButton
移到了单独的类,因此我可以更新状态并仅重建该小部件,因为我遇到的问题是从 ScrollController
中传递数据子类的父类,这在通过导航进行操作时很简单,但在不重建父类的情况下却缝得很尴尬!
I have moved the floatingActionButton
to a separate class so i can update the state and only rebuild that widget the problem i am having is passing the data from the ScrollController
in the parent class to the child this is simple when doing it through navigation but seams a but more awkward without rebuilding the parent!
推荐答案
为获得最佳性能,您可以围绕 Scaffold
创建自己的包装,该包装将 body
作为参数.在 HideFabOnScrollScaffoldState
中调用 setState
时,不会重新构建 body
小部件.
For optimal performance, you can create your own wrapper around Scaffold
that gets the body
as a parameter. The body
widget will not be rebuilt when setState
is called in HideFabOnScrollScaffoldState
.
这是一种常见模式,也可以在诸如 AnimationBuilder
之类的核心小部件中找到.
This is a common pattern that can also be found in core widgets such as AnimationBuilder
.
import 'package:flutter/material.dart';
main() => runApp(MaterialApp(home: MyHomePage()));
class MyHomePage extends StatefulWidget {
@override
State<StatefulWidget> createState() => MyHomePageState();
}
class MyHomePageState extends State<MyHomePage> {
ScrollController controller = ScrollController();
@override
Widget build(BuildContext context) {
return HideFabOnScrollScaffold(
body: ListView.builder(
controller: controller,
itemBuilder: (context, i) => ListTile(title: Text('item $i')),
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.add),
),
controller: controller,
);
}
}
class HideFabOnScrollScaffold extends StatefulWidget {
const HideFabOnScrollScaffold({
Key key,
this.body,
this.floatingActionButton,
this.controller,
}) : super(key: key);
final Widget body;
final Widget floatingActionButton;
final ScrollController controller;
@override
State<StatefulWidget> createState() => HideFabOnScrollScaffoldState();
}
class HideFabOnScrollScaffoldState extends State<HideFabOnScrollScaffold> {
bool _fabVisible = true;
@override
void initState() {
super.initState();
widget.controller.addListener(_updateFabVisible);
}
@override
void dispose() {
widget.controller.removeListener(_updateFabVisible);
super.dispose();
}
void _updateFabVisible() {
final newFabVisible = (widget.controller.offset == 0.0);
if (_fabVisible != newFabVisible) {
setState(() {
_fabVisible = newFabVisible;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: widget.body,
floatingActionButton: _fabVisible ? widget.floatingActionButton : null,
);
}
}
或者,您也可以为 FloatingActionButton
创建包装器,但这可能会中断过渡.
Alternatively you could also create a wrapper for FloatingActionButton
, but that will probably break the transition.
这篇关于子窗口小部件的Flutter setState无需重建父窗口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!