动态更改 Streambuilder 中的流

Change a stream in Streambuilder dynamically

我正在使用 StreamBuilder 在列表中显示来自 Firebase 的一组元素。问题是我需要过滤和更新从 Streambuilder 更改流的列表。我不知道谁能做到这一点。我阅读了有关 Streamcontroller 的信息,并尝试使用它,但它抛出一个错误(“StateError(错误状态:在执行 addStream 时无法添加新事件)”)。 拜托,我不知道该怎么办:( 非常感谢!

以下是代码的重要部分:

class _widget_productosState extends State<widget_productos> {
  final User? usuario = FirebaseAuth.instance.currentUser;
  final firestoreInstance = FirebaseFirestore.instance;
  List<dynamic> lista_alergenos = [];
  var nombre_filtro = TextEditingController();
  var nombre = '';
  Stream<QuerySnapshot> stream_datos = FirebaseFirestore.instance.collection('Producto').snapshots();
  StreamController<QuerySnapshot> controller = StreamController<QuerySnapshot>.broadcast();
  
  @override
  void initState() {
    super.initState();
    stream_datos.forEach((element) {
      controller.add(element);
   });
  }
  
  @override
  Widget build(BuildContext context) {
    List<String> filtro_alergenos = [];

    return 
    SafeArea(child:
    Scaffold(
      backgroundColor: Color.fromARGB(255, 239, 241, 245),
      body: StreamBuilder(
        stream: controller.stream,//stream_datos, //nombre == '' ? firestoreInstance.collection('Producto').snapshots() : firestoreInstance.collection('Producto').where('nombre', isEqualTo: nombre).snapshots(),
        builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
          if (!snapshot.hasData) {
            return new Center(child: new CircularProgressIndicator());
          }
      return 
        Stack(children: [
          Column(children:[
          Container(
                child: DecoratedBox(
                  decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(1.0),
                      border: Border.all(
                          color: Colors.grey.withOpacity(0.5), width: 1.0),
                      color: Color.fromARGB(255, 255, 255, 255)),
                  child: Row(
                    children: [
                      IconButton(
                        (...)
                        ),
                        onPressed: () {
                          showDialog(
                            context: context,
                            builder: (_) =>mostrar_filtros(filtro_alergenos)
                          );
                        },
                      ),
                      Expanded(
                        (...)
                      ),
                      IconButton(
                        (...)
                        ),
                        onPressed: () {
                          setState(() {
                            nombre = nombre_filtro.text;
                            if(nombre==''){
                              controller.stream.drain();
                              setState(() {
                                
                                controller.addStream(stream_datos);
                              });
                              //stream_datos = firestoreInstance.collection('Producto').where('nombre', isEqualTo: nombre).snapshots();
                            }else{
                                stream_datos = firestoreInstance.collection('Producto').where('nombre', isEqualTo: nombre).snapshots();
                                controller.stream.drain();
                                controller.addStream(stream_datos);
                              setState(() {
                                print("ey");
                              });
                              //stream_datos = firestoreInstance.collection('Producto').snapshots();
                            }
                          });
                        },
                      ),

(...)

您可以不使用 StreamController 而是在执行过滤器时保留对 Stream 的引用,例如:


Stream? filterStream;
String? filterValue;

// you can create a method that performs the filtering for you, such as:

void resetStreamWithNameFilter() {
  
    setState(() {
      
      // return all products if your filter is empty
      if (filter.isEmpty) {
        filterStream = FirebaseFirestore.instance.collection('Producto').snapshots();
        return;
      }
      
      // if the filter is not empty, then filter by that field 'nombre'
      valueStream = FirebaseFirestore.instance.collection('team').where('nombre', isEqualTo: filter).snapshots();
    });
  }

那么在你的构建方法中,这将是你调用的第一个方法;还使用新创建的 filterStream 字段,如:

@override
Widget build(BuildContext context) {
    
    // call it initially, to reset the stream
    resetStreamWithNameFilter();
   
    return StreamBuilder(
      stream: filterStream,
      builder: (context, snapshot) {

         // do what you want to do here, but trigger the filter accordingly
         List<QueryDocumentSnapshot> docs = (snapshot.data as QuerySnapshot).docs;
         
         return Column(
            children: [
              Text(docs.length.toString()),
              TextButton(
                onPressed: () {

                   // for example, filter by all products named 'camisa'
                   filterString = 'camisa';
                   
                   // then, execute the resetStreamWithNameFilter
                   resetStreamWithNameFilter();
                }
              )
            ]
         );
      }
    );
}

我创建了一个 Gist 这样你就可以理解了。 运行 在 DartPad 上查看它。