颤振:使用ListView实现StreamBuilder中数据的搜索功能
在我的Flitter应用程序中,我有一个包含所有用户的屏幕。用户列表由颤振:使用ListView实现StreamBuilder中数据的搜索功能,listview,flutter,dart,stream-builder,Listview,Flutter,Dart,Stream Builder,在我的Flitter应用程序中,我有一个包含所有用户的屏幕。用户列表由StreamBuilder生成,它从Cloud Firestore获取数据,并在列表视图中显示用户。为了改进功能,我希望能够使用Appbar中的搜索栏搜索此用户列表 我已经尝试过了,效果很好,但我不知道如何使用StreamBuilder来实现它。作为一个颤振初学者,我将感谢任何帮助!下面是我的用户屏幕和StreamBuilder import 'package:flutter/material.dart'; import 'p
StreamBuilder
生成,它从Cloud Firestore获取数据,并在列表视图中显示用户。为了改进功能,我希望能够使用Appbar
中的搜索栏搜索此用户列表
我已经尝试过了,效果很好,但我不知道如何使用StreamBuilder来实现它。作为一个颤振初学者,我将感谢任何帮助!下面是我的用户屏幕和StreamBuilder
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
class UsersScreen extends StatefulWidget {
static const String id = 'users_screen';
@override
_UsersScreenState createState() => _UsersScreenState();
}
class _UsersScreenState extends State<UsersScreen> {
static Map<String, dynamic> userDetails = {};
static final String environment = userDetails['environment'];
Widget appBarTitle = Text('Manage all users');
Icon actionIcon = Icon(Icons.search);
final TextEditingController _controller = TextEditingController();
String approved = 'yes';
getData() async {
FirebaseUser user = await FirebaseAuth.instance.currentUser();
return await _firestore
.collection('users')
.document(user.uid)
.get()
.then((val) {
userDetails.addAll(val.data);
}).whenComplete(() {
print('${userDetails['environment']}');
setState(() {});
});
}
_printLatestValue() {
print('value from searchfield: ${_controller.text}');
}
@override
void initState() {
getData();
_controller.addListener(_printLatestValue);
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: appBarTitle,
actions: <Widget>[
IconButton(
icon: actionIcon,
onPressed: () {
setState(() {
if (this.actionIcon.icon == Icons.search) {
this.actionIcon = Icon(Icons.close);
this.appBarTitle = TextField(
controller: _controller,
style: TextStyle(
color: Colors.white,
),
decoration: InputDecoration(
prefixIcon: Icon(Icons.search, color: Colors.white),
hintText: "Search...",
hintStyle: TextStyle(color: Colors.white)),
onChanged: (value) {
//do something
},
);
} else {
this.actionIcon = Icon(Icons.search);
this.appBarTitle = Text('Manage all users');
// go back to showing all users
}
});
},
),
]),
body: SafeArea(
child: StreamUsersList('${userDetails['environment']}', approved),
),
);
}
}
我将其传递到StreamUsersList
并将其添加到初始化中。在ListView.Builder
中,我添加了一个if语句,其中包含(snapshot.data.documents[index].data['login'].contains(searchResult))
。有关示例,请参见myListView.Builder的以下代码
else if (snapshot.hasData) {
return ListView.builder(
padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 20.0),
itemCount: snapshot.data.documents.length,
itemBuilder: (BuildContext context, int index) {
DocumentSnapshot user = snapshot.data.documents[index];
final record3 = Record3.fromSnapshot(user);
String unitNr = user.data['unit'];
if (user.data['login'].contains(searchResult) ||
user.data['name'].contains(searchResult) ||
user.data['unit'].contains(searchResult)) {
return Padding(
padding: EdgeInsets.symmetric(
horizontal: 7.0,
vertical: 3.0,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
//This CardCustom is just a Card with some styling
CardCustomUsers(
title: unitNr,
color: Colors.white,
weight: FontWeight.bold,
subTitle:
'${user.data['name']}\n${user.data['login']}',
),
],
),
);
} else {
return Visibility(
visible: false,
child: Text(
'no match',
style: TextStyle(fontSize: 4.0),
),
);
}
});
} else {
return Center(
child: Text('Something is wrong'),
);
}
else if(snapshot.hasData){
返回ListView.builder(
填充:边缘组。对称(水平:10.0,垂直:20.0),
itemCount:snapshot.data.documents.length,
itemBuilder:(构建上下文,int索引){
DocumentSnapshot user=snapshot.data.documents[index];
最终记录3=记录3.fromSnapshot(用户);
字符串unitNr=user.data['unit'];
if(user.data['login']包含(searchResult)||
user.data['name'].包含(searchResult)||
user.data['unit'].contains(searchResult)){
返回填充(
填充:EdgeInsets.symmetric(
水平:7.0,
垂直:3.0,
),
子:列(
crossAxisAlignment:crossAxisAlignment.start,
儿童:[
//这张卡片只是一张带有一些样式的卡片
信用卡用户(
标题:unitNr,
颜色:颜色,白色,
重量:fontwweight.bold,
字幕:
“${user.data['name']}\n${user.data['login']}”,
),
],
),
);
}否则{
返回可见性(
可见:假,
子:文本(
“没有对手”,
样式:TextStyle(fontSize:4.0),
),
);
}
});
}否则{
返回中心(
孩子:文本(‘有什么不对劲’),
);
}
您可以采取以下方法
您将在快照中收到完整的数据
具有如下小部件的层次结构:
StreamBuilder(
ValueListenableBuilder(
ListView.Builder
)
)
创建ValueNotifier并将其交给ValueListenable builder
使用搜索视图更改ValueNotifier的值
当ValueNotifier的值更改时,ListView.builder将重新生成,此时,如果您根据查询将过滤列表提供给ListView.builder,则它将按您希望的方式为您工作
我希望这有帮助,如果有任何疑问,请让我知道
已编辑
您不需要ValueNotifier,而是需要StreamBuilder。因此,小部件的最终层次结构是:
StreamBuilder(
StreamBuilder>(
ListView.Builder
)
)
我没有像你这样的环境,所以我模仿了它并创建了一个例子。你可以参考它,我希望它能给你一些想法来解决你的问题。以下是您可以参考的工作代码:
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(
home: Scaffold(
appBar: AppBar(),
body: SearchWidget(),
),
));
class SearchWidget extends StatelessWidget {
SearchWidget({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(
children: <Widget>[
TextField(onChanged: _filter),
StreamBuilder<List<User>>( // StreamBuilder<QuerySnapshot> in your code.
initialData: _dataFromQuerySnapShot, // you won't need this. (dummy data).
// stream: Your querysnapshot stream.
builder:
(BuildContext context, AsyncSnapshot<List<User>> snapshot) {
return StreamBuilder<List<User>>(
key: ValueKey(snapshot.data),
initialData: snapshot.data,
stream: _stream,
builder:
(BuildContext context, AsyncSnapshot<List<User>> snapshot) {
print(snapshot.data);
return ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return Text(snapshot.data[index].name);
},
);
},
);
},
)
],
),
);
}
}
StreamController<List<User>> _streamController = StreamController<List<User>>();
Stream<List<User>> get _stream => _streamController.stream;
_filter(String searchQuery) {
List<User> _filteredList = _dataFromQuerySnapShot
.where((User user) => user.name.toLowerCase().contains(searchQuery.toLowerCase()))
.toList();
_streamController.sink.add(_filteredList);
}
List<User> _dataFromQuerySnapShot = <User>[
// every user has same enviornment because you are applying
// such filter on your query snapshot.
// same is the reason why every one is approved user.
User('Zain Emery', 'some_enviornment', true),
User('Dev Franco', 'some_enviornment', true),
User('Emilia ONeill', 'some_enviornment', true),
User('Zohaib Dale', 'some_enviornment', true),
User('May Mcdougall', 'some_enviornment', true),
User('LaylaRose Mitchell', 'some_enviornment', true),
User('Beck Beasley', 'some_enviornment', true),
User('Sadiyah Walker', 'some_enviornment', true),
User('Mae Malone', 'some_enviornment', true),
User('Judy Mccoy', 'some_enviornment', true),
];
class User {
final String name;
final String environment;
final bool approved;
const User(this.name, this.environment, this.approved);
@override
String toString() {
return 'name: $name environment: $environment approved: $approved';
}
}
导入'dart:async';
进口“包装:颤振/材料.省道”;
void main()=>runApp(MaterialApp(
家:脚手架(
appBar:appBar(),
正文:SearchWidget(),
),
));
类SearchWidget扩展了无状态Widget{
SearchWidget({Key}):超级(Key:Key);
@凌驾
小部件构建(构建上下文){
返回SingleChildScrollView(
子:列(
儿童:[
文本字段(一旦更改:_过滤器),
StreamBuilder(//StreamBuilder在代码中。
initialData:\u dataFromQuerySnapShot,//您不需要这个。(虚拟数据)。
//流:您的querysnapshot流。
建设者:
(BuildContext上下文,异步快照){
返回流生成器(
key:ValueKey(快照数据),
initialData:snapshot.data,
溪流:_溪流,
建设者:
(BuildContext上下文,异步快照){
打印(快照数据);
返回ListView.builder(
收缩膜:对,
itemCount:snapshot.data.length,
itemBuilder:(构建上下文,int索引){
返回文本(snapshot.data[index].name);
},
);
},
);
},
)
],
),
);
}
}
StreamController _StreamController=StreamController();
Stream get _Stream=>_streamController.Stream;
_过滤器(字符串搜索查询){
列表_filteredList=_dataFromQuerySnapShot
.where((User)=>User.name.toLowerCase()包含(searchQuery.toLowerCase())
.toList();
_streamController.sink.add(_filteredList);
}
列表_dataFromQuerySnapShot=[
//每个用户都有相同的环境,因为您正在申请
//在查询快照上设置这样的过滤器。
//这也是为什么每个人都是被批准的用户的原因。
用户('Zain Emery','some_environment',true),
用户('
else if (snapshot.hasData) {
return ListView.builder(
padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 20.0),
itemCount: snapshot.data.documents.length,
itemBuilder: (BuildContext context, int index) {
DocumentSnapshot user = snapshot.data.documents[index];
final record3 = Record3.fromSnapshot(user);
String unitNr = user.data['unit'];
if (user.data['login'].contains(searchResult) ||
user.data['name'].contains(searchResult) ||
user.data['unit'].contains(searchResult)) {
return Padding(
padding: EdgeInsets.symmetric(
horizontal: 7.0,
vertical: 3.0,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
//This CardCustom is just a Card with some styling
CardCustomUsers(
title: unitNr,
color: Colors.white,
weight: FontWeight.bold,
subTitle:
'${user.data['name']}\n${user.data['login']}',
),
],
),
);
} else {
return Visibility(
visible: false,
child: Text(
'no match',
style: TextStyle(fontSize: 4.0),
),
);
}
});
} else {
return Center(
child: Text('Something is wrong'),
);
}
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(
home: Scaffold(
appBar: AppBar(),
body: SearchWidget(),
),
));
class SearchWidget extends StatelessWidget {
SearchWidget({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(
children: <Widget>[
TextField(onChanged: _filter),
StreamBuilder<List<User>>( // StreamBuilder<QuerySnapshot> in your code.
initialData: _dataFromQuerySnapShot, // you won't need this. (dummy data).
// stream: Your querysnapshot stream.
builder:
(BuildContext context, AsyncSnapshot<List<User>> snapshot) {
return StreamBuilder<List<User>>(
key: ValueKey(snapshot.data),
initialData: snapshot.data,
stream: _stream,
builder:
(BuildContext context, AsyncSnapshot<List<User>> snapshot) {
print(snapshot.data);
return ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return Text(snapshot.data[index].name);
},
);
},
);
},
)
],
),
);
}
}
StreamController<List<User>> _streamController = StreamController<List<User>>();
Stream<List<User>> get _stream => _streamController.stream;
_filter(String searchQuery) {
List<User> _filteredList = _dataFromQuerySnapShot
.where((User user) => user.name.toLowerCase().contains(searchQuery.toLowerCase()))
.toList();
_streamController.sink.add(_filteredList);
}
List<User> _dataFromQuerySnapShot = <User>[
// every user has same enviornment because you are applying
// such filter on your query snapshot.
// same is the reason why every one is approved user.
User('Zain Emery', 'some_enviornment', true),
User('Dev Franco', 'some_enviornment', true),
User('Emilia ONeill', 'some_enviornment', true),
User('Zohaib Dale', 'some_enviornment', true),
User('May Mcdougall', 'some_enviornment', true),
User('LaylaRose Mitchell', 'some_enviornment', true),
User('Beck Beasley', 'some_enviornment', true),
User('Sadiyah Walker', 'some_enviornment', true),
User('Mae Malone', 'some_enviornment', true),
User('Judy Mccoy', 'some_enviornment', true),
];
class User {
final String name;
final String environment;
final bool approved;
const User(this.name, this.environment, this.approved);
@override
String toString() {
return 'name: $name environment: $environment approved: $approved';
}
}