flutter - 字符串列表不会在 setState 上更新
问题描述
我正在尝试学习 Flutter,但无法理解这里出了什么问题。我有主小部件(Flutter starter 应用程序附带的那个),我删除了主体,并添加了一个SearchBar
小部件和一个PhotoList
小部件,我正在尝试从 API 获取数据,并更新 PhotoList 小部件以显示图像我取了。
这就是我所拥有的:
class _MyHomePageState extends State<MyHomePage> {
int _selectedSegment = 0;
Networking _service = Networking();
List<String> urls;
@override
void initState() {
urls = [];
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
margin: EdgeInsets.only(top: 100),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SearchBar(
onSearchTap: (String value) {
Map<String, dynamic> map;
List<dynamic> results;
dynamic urls;
dynamic thumbs;
List<String> image_urls = new List<String>();
_service.fetchPhotos(value).then((value) => {
map = jsonDecode(value.body),
results = map["results"],
thumbs = results.map((e) => e["urls"]),
for (dynamic thumb in thumbs)
{image_urls.add(thumb["thumb"].toString())},
this.setState(() {
urls = image_urls;
})
});
},
),
],
),
Padding(
padding: const EdgeInsets.fromLTRB(16, 16, 16, 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ButtonGroup(
titles: ["Photos", "Collections", "User"],
current: _selectedSegment,
onTab: (selected) {
setState(() {
_selectedSegment = selected;
});
},
),
],
),
),
PhotosGrid(urls: urls),
],
),
),
);
}
}
我在 setState 之后打印了 url,它确实有打印到控制台的值。但它不会在 PhotosGrid 中更新,据我了解,setState 应该刷新build
函数,所以 PhotosGrid 也应该刷新,但没有任何反应。这是我的 PhotosGrid 小部件:
class PhotosGrid extends StatefulWidget {
List<String> urls;
PhotosGrid({Key key, this.urls}) : super(key: key);
@override
_PhotosGridState createState() => _PhotosGridState();
}
class _PhotosGridState extends State<PhotosGrid> {
@override
Widget build(BuildContext context) {
return Expanded(
child: Container(
child: ListView(
children: <Widget>[
for (var url in widget.urls) PhotoCard(url)
//for (var url in widget.urls) PhotoCard(url),
],
),
),
);
}
}
这是我的照片卡:
class PhotoCard extends StatefulWidget {
String imageUrl;
PhotoCard({Key key, this.imageUrl}) : super(key: key);
@override
_PhotoCardState createState() => _PhotoCardState();
}
class _PhotoCardState extends State<PhotoCard> {
@override
Widget build(BuildContext context) {
return Container(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 32),
child: Container(
height: 220,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
image: DecorationImage(
image: NetworkImage(widget.imageUrl),
fit: BoxFit.cover,
)),
),
),
);
}
}
我不明白这里出了什么问题。
解决方案
老实说,我觉得很奇怪,这首先不起作用
onSearchTap: (String value) {
Map<String, dynamic> map;
List<dynamic> results;
// dynamic urls; delete this line
List<String> image_urls = <String>[];
// does this future completes without error?
_service.fetchPhotos(value).then((value) => {
map = jsonDecode(value.body),
results = map["results"],
thumbs = results.map((e) => e["urls"]),
for (dynamic thumb in thumbs)
image_urls.add(thumb["thumb"].toString()),
setState(() => urls = image_urls)
});
},
更新
我刚刚制作了一个最小的可重现项目并毫无问题地运行它
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.light(),
debugShowCheckedModeBanner: false,
home: MyHomePage());
}
}
Future<List<String>> thumbnails(int value) {
String url = 'https://picsum.photos/id/x/200/300'; //dummy api to retrieve pics
List<String> myThumbs = [];
int n = value ?? 0;
for(int i = 0; i < n; i++) myThumbs.add(
url.replaceFirst('x', i.toString()) //just change x for any number to retrieve a real url from the api
);
myThumbs.shuffle();
return Future<List<String>>.value(myThumbs);
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<String> urls;
@override
void initState() {
urls = <String>[];
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
margin: EdgeInsets.only(top: 100),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 5),
child: TextField(
key: Key('MyTextField'),
onSubmitted: (String value) {
thumbnails(int.tryParse(value)).then((list) {
setState(() => urls = list);
});
},
),
),
PhotosGrid(urls: urls),
],
),
),
);
}
}
class PhotosGrid extends StatefulWidget {
final List<String> urls;
PhotosGrid({Key key, this.urls}) : super(key: key);
@override
_PhotosGridState createState() => _PhotosGridState();
}
class _PhotosGridState extends State<PhotosGrid> {
@override
Widget build(BuildContext context) {
return Expanded(
child: Container(
child: ListView(
children: <Widget>[
for (var url in widget.urls) PhotoCard(imageUrl: url)
],
),
),
);
}
}
class PhotoCard extends StatefulWidget {
final String imageUrl;
PhotoCard({Key key, this.imageUrl}) : super(key: key);
@override
_PhotoCardState createState() => _PhotoCardState();
}
class _PhotoCardState extends State<PhotoCard> {
@override
Widget build(BuildContext context) {
return Container(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 32),
child: Container(
height: 220,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
image: DecorationImage(
image: NetworkImage(widget.imageUrl),
fit: BoxFit.cover,
)),
),
),
);
}
}
而不是你的 SearchBar 我只是放了一个 TextField (因为我没有 SearchBar 类,但它应该工作相同)。提交后,我尝试将其解析为一个数字(请插入数字),然后从图片的虚拟 api 创建一个列表(我没有您正在使用的服务)。想法是一样的,我仍然使用你所有的类并且运行它没有问题
我唯一的建议是尽量减少变量的数量(或仅在需要它们的地方创建它们),如果您已经知道您期望的值类型,请避免使用动态
onSearchTap: (String value) {
_service.fetchPhotos(value).then((value) => {
//declare them here if you only will use them inside the then future
Map<String, dynamic> map = jsonDecode(value.body),
List<dynamic> results = map["results"],
var thumbs = results.map((e) => e["urls"]),
List<String> image_urls = <String>[];
for (var thumb in thumbs) image_urls.add(thumb["thumb"].toString()),
setState(() => urls = image_urls);
});
},
推荐阅读
- jquery - 如何在 jquery 脚本中输出 Coldfusion 变量?
- javascript - 我是编程新手。我想从javascript中的数组中删除两个重复项
- python - 不和谐.py | 排序成员的
- firebase - Firebase Auth - 将 REST 响应传递给 JS SDK 以登录用户
- ios - Xcode SwiftUI - 显示来自两个连接项的信息
- javascript - 在独立 GCP Node.js 函数上使用 Oauth0 服务器验证 Jwt 令牌的步骤
- javascript - 如何在 React 中处理事件冒泡
- dotnetnuke - (-2:未指定的错误)失败:fs.is_open()。无法在函数“cv::dnn::ReadProtoFromTextFile”中打开“deploy_age.prototxt”
- javascript - 限制 JavaScript 中的函数范围(滑块用例)?
- php - 为什么不使用 file_get_contents PHP 函数发布数据?