我正在尝试学习Flutter,无法理解这里出了什么问题。
我有主窗口小部件(Flutter入门应用程序随附的窗口小部件),删除了主体,并添加了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,
)),
),
),
);
}
}
我不明白这里出了什么问题。
答案 0 :(得分:0)
说实话,我发现这根本不起作用
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,
)),
),
),
);
}
}
我只是放置了一个TextField而不是您的SearchBar(因为我没有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);
});
},