简体   繁体   English

如何在 flutter 中使用 Streambuilder

[英]How to use Streambuilder in flutter

import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';

void main() async {
  //Run this first
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Smart Bin',
      home: new HomePageWidget(),
    );
  }
}

class HomePageWidget extends StatefulWidget {
  const HomePageWidget({Key key}) : super(key: key);

  @override
  _HomePageWidgetState createState() => _HomePageWidgetState();
}

class _HomePageWidgetState extends State<HomePageWidget> {
  final scaffoldKey = GlobalKey<ScaffoldState>();
  final currentBinRecord = FirebaseFirestore.instance.collection("current_bin");


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: scaffoldKey,
      appBar: AppBar(
        title: Text(
          'SmartBin',
        ),
      ),
      body: SafeArea(
        child: GestureDetector(
          onTap: () => FocusScope.of(context).unfocus(),
          child: Column(
            mainAxisSize: MainAxisSize.max,
            children: [
              Expanded(
                child: StreamBuilder<List<CurrentBinRecord>>(
                  stream: queryCurrentBinRecord(
                    queryBuilder: (currentBinRecord) =>
                        currentBinRecord.orderBy('level', descending: true),
                  ),
                  builder: (context, snapshot) {
                    // Customize what your widget looks like when it's loading.
                    if (!snapshot.hasData) {
                      return Center(
                        child: SizedBox(
                          width: 50,
                          height: 50,
                          child: CircularProgressIndicator(),
                        ),
                      );
                    }
                    List<CurrentBinRecord> listViewCurrentBinRecordList =
                        snapshot.data;
                    return ListView.builder(
                      padding: EdgeInsets.zero,
                      scrollDirection: Axis.vertical,
                      itemCount: listViewCurrentBinRecordList.length,
                      itemBuilder: (context, listViewIndex) {
                        final listViewCurrentBinRecord =
                            listViewCurrentBinRecordList[listViewIndex];
                        return Row(
                          mainAxisSize: MainAxisSize.max,
                          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                          children: [
                            Text(
                              listViewCurrentBinRecord.area,
                            ),
                            Text(
                              listViewCurrentBinRecord.level.toString(),
                            ),
                          ],
                        );
                      },
                    );
                  },
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

This is the error这是错误

First error is on:第一个错误是:

child: StreamBuilder<List<CurrentBinRecord>>

The name 'CurrentBinRecord' isn't a type so it can't be used as a type argument.名称“CurrentBinRecord”不是类型,因此不能用作类型参数。 Try correcting the name to an existing type, or defining a type named 'CurrentBinRecord'.尝试将名称更正为现有类型,或定义名为“CurrentBinRecord”的类型。

Second error is on:第二个错误是:

stream: queryCurrentBinRecord

The method 'queryCurrentBinRecord' isn't defined for the type '_HomePageWidgetState'.未为类型“_HomePageWidgetState”定义方法“queryCurrentBinRecord”。 Try correcting the name to the name of an existing method, or defining a method named 'queryCurrentBinRecord'.尝试将名称更正为现有方法的名称,或定义名为“queryCurrentBinRecord”的方法。

Third error is on:第三个错误是:

List<CurrentBinRecord> listViewCurrentBinRecordList =
                        snapshot.data;

The name 'CurrentBinRecord' isn't a type so it can't be used as a type argument.名称“CurrentBinRecord”不是类型,因此不能用作类型参数。 Try correcting the name to an existing type, or defining a type named 'CurrentBinRecord'.尝试将名称更正为现有类型,或定义名为“CurrentBinRecord”的类型。

These is the syntax try -这些是语法尝试 -

return StreamBuilder(
  stream: theStreamSource, // Eg a firebase query
  builder: (context, AsyncSnapshot snapshot) {
    if (!snapshot.hasData) {
       return Center(
         child: CircularProgressIndicator(),
       );
    }
    return ListView.builder(
        itemCount: snapshot.data.documents.length,
        itemBuilder: (context, int index) {
          return Text(snapshot.data.documents[index]['title']);
        }
    );
  },
);

Hope it helps.希望能帮助到你。

I think the best way to use StreamBuilder is to create separate controller class that can handle all your business logic and update UI.我认为使用 StreamBuilder 的最佳方式是创建单独的控制器类来处理您的所有业务逻辑和更新 UI。

// your widget class
class UIClass extends StatefulWidget {


  const UIClass({Key key}) : super(key: key);

  @override
  _UIClassState createState() => _UIClassState();
}

class _UIClassState extends State<UIClass> {

  UIClassController<List<CurrentBinRecord>> _uiController;

  @override
  void initState() {
    _uiController = UIClassController(StreamController<List<CurrentBinRecord>>());
    super.initState();
  }
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text("Hello Everyone"),
        StreamBuilder<List<CurrentBinRecord>>(
          stream: _uiController.uiStream,
          builder: (context, snapshot) {
             if(snapshot.hasError){
               return ErrorWidget();
             }
             else if(snapshot.connectionState == ConnectionState.waiting){
               return WaitingWidget();
             }
             else if(snapshot.hasData){
               return ListView.builder(
                 padding: EdgeInsets.zero,
                 scrollDirection: Axis.vertical,
                 itemCount: snapshot.data.length,
                 itemBuilder: (context, listViewIndex) {
                   final listViewCurrentBinRecord =
                   snapshot.data[listViewIndex];
                   return Row(
                     mainAxisSize: MainAxisSize.max,
                     mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                     children: [
                       Text(
                         listViewCurrentBinRecord.area,
                       ),
                       Text(
                         listViewCurrentBinRecord.level.toString(),
                       ),
                     ],
                   );
                 },
               );
             }
             else{
               return SizedBox();
             }
          }
        ),
      ],
    );
  }

  @override
  void dispose() {
    super.dispose();
    _uiController.dispose();
  }
}


// controller class to handle all business logic
// you can also split it into multiple sub controllers
class UIClassController<T> {

  final StreamController<T> _controller;

  // If you are using this on multiple widgets then  use asBroadcastStream()
  Stream<T> get uiStream => _controller.stream;

  UIClassController(this._controller);

  void updateMyUI([dynamic params]){
       T t;
      // your logic //
      //------------//
      _controller.sink.add(t);
  }

  void dispose(){
    _controller.close();
  }

}

Code I'm Using for StreamBuilder我用于 StreamBuilder 的代码

        import 'package:cloud_firestore/cloud_firestore.dart';
        import 'package:firebase_auth/firebase_auth.dart';
        import 'package:flutter/material.dart';
        import '../door/widgets/Navbar.dart';
        import '../door/widgets/sidenav.dart';
        import 'package:get/get.dart';

        FirebaseAuth auth = FirebaseAuth.instance;

        class CartPage extends StatefulWidget {
          @override
          _CartPageState createState() => _CartPageState();
        }

        class _CartPageState extends State<CartPage> {
          final FirebaseFirestore fb = FirebaseFirestore.instance;
          int up = 1;
          bool loading = false;
          final ScrollController _scrollController = ScrollController();

          @override
          void initState() {
            super.initState();
            getCartData();
          }

          void addMore(qty, documentID) {
            int new_qty = qty + 1;
            Get.snackbar('Qty! ', new_qty.toString());
            String collection_name = "cart_${auth.currentUser?.email}";
            FirebaseFirestore.instance
                .collection(collection_name)
                .doc(documentID)
                .update({
              'qty': new_qty,
              'updated_at': Timestamp.now(),
            }) // <-- Your data
                .then((_) => print('Added'))
                .catchError((error) => Get.snackbar('Failed!', 'Error: $error'));
          }

          void minusMore(qty, documentID) {
            if (qty > 1) {
              int new_qty = qty - 1;
              String collection_name = "cart_${auth.currentUser?.email}";
              FirebaseFirestore.instance
                  .collection(collection_name)
                  .doc(documentID)
                  .update({
                'qty': new_qty,
                'updated_at': Timestamp.now(),
              }) // <-- Your data
                  .then((_) => print('Subtracted'))
                  .catchError((error) => Get.snackbar('Failed!', 'Error: $error'));
            }
          }

          Stream<QuerySnapshot> getCartData() {
            String collection_name = "cart_${auth.currentUser?.email}";
            return FirebaseFirestore.instance
                .collection(collection_name)
                .orderBy("created_at", descending: false)
                .snapshots();
          }

          final ButtonStyle style = ElevatedButton.styleFrom(
              minimumSize: Size(50, 30),
              backgroundColor: Color(0xFFFFB61A),
              elevation: 6,
              textStyle: const TextStyle(fontSize: 11),
              shape: const RoundedRectangleBorder(
                  borderRadius: BorderRadius.all(
                    Radius.circular(20),
                  )));

          @override
          Widget build(BuildContext context) {
            return Scaffold(
              appBar: Navbar.navbar(),
              drawer: Sidenav.sidenav(),
              body: Container(
                padding: EdgeInsets.all(10.0),
                child: StreamBuilder<QuerySnapshot>(
                  stream: getCartData(),
                  builder: (context, snapshot) {
                    switch (snapshot.connectionState) {
                      case ConnectionState.waiting:
                        return Center(child: CircularProgressIndicator());
                      default:
                        if (snapshot.hasError) {
                          return buildText('Something Went Wrong Try later');
                        } else {
                          if (!snapshot.hasData) {
                            return Card(
                              child: Column(
                                mainAxisSize: MainAxisSize.min,
                                children: <Widget>[
                                  ListTile(
                                    leading: ConstrainedBox(
                                      constraints: const BoxConstraints(
                                        minWidth: 100,
                                        minHeight: 190,
                                        maxWidth: 200,
                                        maxHeight: 200,
                                      ),
                                      child: Icon(Icons.shopping_cart, size: 45),
                                    ),
                                    title: Text('No Food!'),
                                    subtitle: const Text('Your cart is empty!'),
                                  ),
                                ],
                              ),
                            );
                          } else {
                            return ListView.builder(
                                physics: const BouncingScrollPhysics(),
                                shrinkWrap: true,
                                itemCount: snapshot.data?.docs.length,
                                itemBuilder: (BuildContext context, int index) {
                                  return SizedBox(
                                    height: 90.0,
                                    child: Card(
                                      elevation: 10,
                                      child: Row(
                                        mainAxisAlignment: MainAxisAlignment.start,
                                        crossAxisAlignment:
                                        CrossAxisAlignment.start,
                                        mainAxisSize: MainAxisSize.max,
                                        children: <Widget>[
                                          const SizedBox(
                                            width: 20,
                                          ),
                                          _buildImg('assets/logo.png', '60', '60'),
                                          const SizedBox(
                                            width: 14,
                                          ),
                                          SizedBox(
                                            width:
                                            MediaQuery.of(context).size.width *
                                                0.33,
                                            child: Column(
                                              mainAxisSize: MainAxisSize.max,
                                              crossAxisAlignment:
                                              CrossAxisAlignment.start,
                                              children: <Widget>[
                                                const SizedBox(
                                                  height: 20,
                                                ),
                                                Text(
                                                    snapshot.data?.docs[index]
                                                    ["name"],
                                                    maxLines: 2,
                                                    style: const TextStyle(
                                                        fontWeight: FontWeight.w500,
                                                        fontSize: 14)),
                                                const SizedBox(
                                                  height: 5,
                                                ),
                                                Text(
                                                    "₹${snapshot.data?.docs[index]["price"]}",
                                                    style: const TextStyle(
                                                        fontWeight: FontWeight.w400,
                                                        fontSize: 12)),
                                              ],
                                            ),
                                          ),
                                          const SizedBox(
                                            width: 10,
                                          ),
                                          Container(
                                            margin: const EdgeInsets.only(
                                                top: 20.0, bottom: 10.0),
                                            decoration: BoxDecoration(
                                                color: const Color(0xFFFFB61A),
                                                // color: Color(0xFF0A2031),
                                                borderRadius:
                                                BorderRadius.circular(17)),
                                            child: Row(
                                              mainAxisAlignment:
                                              MainAxisAlignment.spaceBetween,
                                              crossAxisAlignment:
                                              CrossAxisAlignment.end,
                                              children: <Widget>[
                                                SizedBox(
                                                  height: 40,
                                                  child: IconButton(
                                                      onPressed: () {
                                                        minusMore(
                                                            snapshot.data
                                                                ?.docs[index]
                                                            ["qty"],
                                                            snapshot
                                                                .data
                                                                ?.docs[index]
                                                                .reference
                                                                .id);
                                                      },
                                                      color: Colors.white,
                                                      icon:
                                                      const Icon(Icons.remove)),
                                                ),
                                                const SizedBox(
                                                  width: 5,
                                                ),
                                                Container(
                                                  margin: const EdgeInsets.only(
                                                      bottom: 10.0),
                                                  child: Text(
                                                      "${snapshot.data?.docs[index]["qty"]}",
                                                      style: const TextStyle(
                                                          fontWeight:
                                                          FontWeight.w400,
                                                          color: Colors.white,
                                                          fontSize: 16)),
                                                ),
                                                const SizedBox(
                                                  width: 5,
                                                ),
                                                SizedBox(
                                                  height: 40,
                                                  child: IconButton(
                                                      color: Colors.white,
                                                      onPressed: () {
                                                        addMore(
                                                            snapshot.data
                                                                ?.docs[index]
                                                            ["qty"],
                                                            snapshot
                                                                .data
                                                                ?.docs[index]
                                                                .reference
                                                                .id);
                                                      },
                                                      icon: const Icon(Icons.add)),
                                                ),
                                              ],
                                            ),
                                          ),
                                          const SizedBox(
                                            width: 10,
                                          ),
                                        ],
                                      ),
                                    ),
                                  );
                                });
                          }
                        }
                    }
                  },
                ),
              ),
            );
          }

          Widget buildText(String text) => Center(
            child: Text(
              text,
              style: TextStyle(fontSize: 24, color: Colors.black),
            ),
          );

          _buildImg(img, hei, wid) {
            return Container(
              alignment: Alignment.center, // use aligment
              child: Image.asset(
                img,
                height: double.parse(hei),
                width: double.parse(wid),
                fit: BoxFit.cover,
              ),
            );
          }
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM