如何在导航抽屉中更新有状态小部件,同时在 Android 中保持相同的类像片段一样?



我想更新我的类的有状态小部件,同时从导航抽屉从服务器获取数据后返回相同的类。我遇到了问题,即类只加载一次数据,如果我导航到导航抽屉的另一个项目,则保持不变。因为状态只创建一次。

这是我的代码:

class CategoryFilter extends StatefulWidget {
int productIndex;
String category_name;
CategoryFilter(this.productIndex, this.category_name)
{
print("CategoryFilter");
print(productIndex);
print(category_name);
new _CategoryFilterState(productIndex, category_name);
}
@override
_CategoryFilterState createState() => new 
_CategoryFilterState(productIndex, category_name);
}
class _CategoryFilterState extends State<CategoryFilter> {
int productIndex;
List<ResponseDataProducts> productList;
List data;
String category_name;
_CategoryFilterState(this.productIndex, this.category_name)
{
print("CategoryFilter");
print(productIndex);
print(category_name);
}
@override
void initState(){
super.initState();
Future<String> status = getData(productIndex);
status.then((onValue){
if(onValue.toString() == "Success")
{
Navigator.pop(context);
}
});

// this.getData();
}
@override
Widget build(BuildContext context) {
return new Scaffold(
body: new Container(
color: Colors.white30,
child: new ListView.builder(
itemCount: productList == null ? 0 : productList.length,
itemBuilder: (BuildContext context, int index) {
return new Container(
margin: const EdgeInsets.only( bottom: 10.0),
constraints: new BoxConstraints.expand(
height: 200.0
),
alignment: Alignment.bottomLeft,
decoration: new BoxDecoration(
image: new DecorationImage(image:
new NetworkImage
("http://myurl.com/"+productList[index].thumbnail),
fit: BoxFit.cover)
),
child:new Container(
child: new Text(
productList[index].name,
style: new TextStyle(color: Colors.white, fontSize: 30.0),
),
color: Colors.black54,
alignment: new FractionalOffset(0.5, 0.0),
height: 35.0,
// margin: const EdgeInsets.symmetric(vertical: 30.0),
),
);
})
),
) ;
}

void _onLoading()
{
showDialog(context: context,
barrierDismissible: false,
child: progress);
new Future.delayed(new Duration(seconds: 2), (){
// Navigator.pop(context);
});
}

Future<String> getData(int productIndex) async {
productList = new List<ResponseDataProducts>();

_onLoading();
http.Response response = await http.get(
Uri.encodeFull(CommonMethods.base_url + 'product/$productIndex'),
headers: {"Accept": "application/json"});
print(response.body);
setState(() {
var convertDataToJson = JSON.decode(response.body);
data = convertDataToJson["responseData"];
for(int i=0; i<data.length; i++)
{
ResponseDataProducts responseData = new ResponseDataProducts(
data[i]["id"],
data[i]["name"], data[i]["description"],
data[i]["title"], data[i]["thumbnail"]);
productList.add(responseData);
}
//Navigator.pop(context);
});
return "Success";
}
}

以下是我从导航抽屉中调用此类别过滤器类的方式:

_getDraserItemWidget(int pos)
{
switch(pos)
{
case 0:
return new Home(bar_id);

case 1:

return  new CategoryFilter(categoryList[pos-1].id, categoryList[pos-1].name);

case 2:

return  new CategoryFilter(categoryList[pos-1].id, categoryList[pos-1].name);

case 3:

return  new CategoryFilter(categoryList[pos-1].id, categoryList[pos-1].name);

case 4:
return new OpeningTime();

case 5:
break;

}
}

我建议不要调用该方法在类的initState方法中加载数据,而是使用FutureBuilder小部件。如果从导航抽屉返回新FutureBuilder,则每次创建新时都应调用服务,并且通常是执行异步请求的更好方法。

这是一个非常简单的例子。它不能很好地完成抽屉(或其他一些事情 - 只有这么多时间花在这样的事情上(,但它应该说明这个概念。

请注意,它不是"更新小部件",而是创建一个新的小部件。由于 flutter 做事的方式,这应该是相对高性能的,特别是因为你不是一直这样做,而是只当用户从导航菜单中选择某些内容时。

import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatefulWidget {
@override
State<StatefulWidget> createState() => new MyAppState();
}
class MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: new TextPage(text: "Home!"),
);
}
}
Map<int, int> _nums = Map();
class TextPage extends StatelessWidget {
final String text;
const TextPage({Key key, @required this.text}) : super(key: key);
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new PreferredSize(
child: new Container(),
preferredSize: Size.fromHeight(10.0),
),
body: new Center(
child: new Text(text),
),
drawer: new Builder(
builder: (context) => Material(
child: new SafeArea(
child: Column(
children: <Widget>[
new FlatButton(
onPressed: () {
Navigator.pushReplacement(
context, new MaterialPageRoute(builder: (context) => _getDrawerItemWidget(1)));
},
child: Text("First item"),
),
new FlatButton(
onPressed: () {
Navigator.pushReplacement(
context, new MaterialPageRoute(builder: (context) => _getDrawerItemWidget(2)));
},
child: Text("Second item"),
),
],
),
),
),
),
);
}
_getDrawerItemWidget(int i) {
return new FutureBuilder<String>(
builder: (context, AsyncSnapshot<String> snapshot) {
if (snapshot.data != null) {
return new TextPage(text: snapshot.data);
} else {
return new TextPage(text: "Loading.");
}
},
future: () async {
var num = _nums.putIfAbsent(i, () => 0);
_nums[i] = num + 1;
String toReturn = "You retrieved number $i for the $num time";
return await Future.delayed<String>(Duration(seconds: 1), () => toReturn);
}(),
);
}
}

从理论上讲,您可以做一些不同的事情来保留 GlobalKey 引用,并在子小部件上调用方法(如果它与当前选择匹配以使其更新(,但这在 flutter 中通常是一个坏主意 - 最佳实践鼓励您在小部件树中向下传递数据,而不是向下调用函数。如果你必须使用GlobalKeys,你通常可以重构以做得更好。

最新更新