问题描述
问题很简单,但是我找不到合适的解决方案。我有一个搜索屏幕,这是我想要做的。
- 首次启动屏幕时,我想在
Text
小部件中显示一条消息,“您的结果将出现在这里”。 - 如果用户在搜索框中输入内容,然后按搜索,我想显示
CircularProgressIndicator
。 - 然后,当收到API响应时,我想显示
ListView
或Text
说“什么都没找到”。 - 如果用户再次搜索某些内容,我想再次显示
CircularProgressIndicator
。
如何使用Stream
实现此行为?以下是我到目前为止的代码:
小部件
StreamBuilder<List<Model>>(
stream: bloc.searchStream,builder: (context,snapshot) {
if (snapshot.hasError) {
return Center(
child: Text(
'Error occurred'
),);
}
if (!snapshot.hasData) {
return Center(
child: Text(
'Your results will appear here'
),);
}
if (snapshot.hasData && snapshot.data.length < 1) {
return Center(
child: Text(
'Found nothing'
),);
}
// Where should I put my CircularProgressIndicator?
return ListView.separated(
itemCount: snapshot.data.length,separatorBuilder: (context,index) => Divider(height: 1),itemBuilder: (context,index) {
final item = snapshot.data[index];
return ItemWidget(item);
},);
},)
BLoC
final _searchStreamController = StreamController<List<Model>>();
Stream<List<Model>> get searchStream => _searchStreamController.stream;
void search(String searchTerm) async {
if (searchTerm.isEmpty) {
_searchStreamController.add(null);
return;
}
final client = HttpClient();
client.method = HttpMethod.POST;
client.endPoint = 'search';
client.addData('query',searchTerm);
try {
final responseStr = await client.execute();
final response = SearchResponse.fromJson(responseStr);
_searchStreamController.add(response.data);
} catch (e) {
_searchStreamController.addError(e);
}
}
我想每次调用CircularProgressIndicator
函数时显示search(String searchedTerm)
。
谢谢。
解决方法
StreamBuilder<List<Model>>(
stream: bloc.searchStream,builder: (context,snapshot) {
if (snapshot.hasData) {
if (snapshot.data.length ==0){
return Center(
child: Text(
'Found nothing'
),);
}
return ListView.separated(
itemCount: snapshot.data.length,separatorBuilder: (context,index) => Divider(height: 1),itemBuilder: (context,index) {
final item = snapshot.data[index];
return ItemWidget(item);
},);
}else if (snapshot.hasError) {
return Center(
child: Text(
'Error occurred'
),);
}else {
return Center(
child:CircularProgressIndicator()
);
}
},)
给出一个初始Text()小部件,其值为“结果将在此处显示”, 然后在Button的onClick上,将原始的Text()小部件替换为StreamBuilder
,您可以尝试:
StreamBuilder<List<Model>>(
builder: (context,snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Center(child: Text('Your results will appear here'));
case ConnectionState.active:
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
case ConnectionState.done:
if (snapshot.hasError)
return Center(child: Text('Error occurred'));
if (snapshot.data.isEmpty) {
return Container(child: Center(child: Text('Found nothing')));
} else {
return ListView.separated(
itemCount: snapshot.data.length,index) {
final item = snapshot.data[index];
return ItemWidget(item);
},);
}
}
return Center(child: Text('Your results will appear here'));
},)
,
这是我必须达到的骇客。如果有更好的方法可以解决此问题,请发布答案,我将其标记为正确。
黑客
class JugarModel<T> {
bool isProcessing;
T data;
JugarModel({this.isProcessing,this.data});
}
然后使用此isProcessing
属性检查是否显示CircularProgressIndicator
或ListView
。其余代码变为:
小工具
StreamBuilder<JugarModel>(
stream: bloc.searchStream,snapshot) {
if (snapshot.hasError) {
return Center(
child: Text(
'Error occurred'
),);
}
if (!snapshot.hasData) {
return Center(
child: Text(
'Your results will appear here'
),);
}
if (snapshot.hasData && snapshot.data.data.isEmpty) {
if (snapshot.data.isProcessing) {
return Center(
child: CircularProgressIndicator(),);
} else {
return Center(
child: Text(
'Found nothing'
),);
}
}
return ListView.separated(
itemCount: snapshot.data.data.length,index) {
final item = snapshot.data.data[index];
return ItemWidget(item);
},);
},)
BLoC
final _searchStreamController = StreamController<JugarModel<List<Data>>>();
Stream<JugarModel<List<Data>>> get searchStream => _searchStreamController.stream;
void search(String searchTerm) async {
if (searchTerm.isEmpty) {
_searchStreamController.add(null);
return;
}
final client = HttpClient();
client.method = HttpMethod.POST;
client.endPoint = 'search';
client.addData('query',searchTerm);
// This MAGIC line will call StreamBuilder callback with isProcessing set to true.
_searchStreamController.add(JugarModel<List<Data>>(isProcessing: true,data: List()));
try {
final responseStr = await client.execute();
final response = SearchResponse.fromJson(responseStr);
// And after we've received response from API and parsed it,we're calling StreamBuilder
// callback again with isProcessing set to false.
_searchStreamController.add(JugarModel<List<Data>>(isProcessing: false,data: response.data));
} catch (e) {
_searchStreamController.addError(e);
}
}