简体   繁体   English

Flutter/Firestore:如何在 ListTile 中显示来自 doc 的数据?

[英]Flutter/Firestore : How do I display data from doc in a ListTile?

I am new to Flutter/Firebase/Firestore etc.. so I am struggling a bit.我是 Flutter/Firebase/Firestore 等的新手。所以我有点挣扎。 I want to grab the data from the documents in my 'users' collection in Firestore and display it in my account information page.我想从 Firestore 中我的“用户”集合中的文档中获取数据,并将其显示在我的帐户信息页面中。 I have spent hours messing around with this and I am stuck.我已经花了几个小时搞砸这个,我被困住了。 If anybody could help me out that would be wonderful!如果有人可以帮助我,那就太好了!

Here are some samples of what my code, app, and firestore look like.以下是我的代码、应用程序和 Firestore 的一些示例。

Code:代码:

signup.dart - this is the page that creates the doc in Firebase on signup signup.dart - 这是在注册时在 Firebase 中创建文档的页面

 class SignUp extends StatefulWidget { const SignUp({Key? key}): super(key: key); @override State<SignUp> createState() => _SignUpState(); } class _SignUpState extends State<SignUp> { var emailController = TextEditingController(); var passwordController = TextEditingController(); /* var docId = FirebaseFirestore.instance.collection('users').doc().id; */ final TextEditingController _usernameController = TextEditingController(); final TextEditingController _phoneNumberController = TextEditingController(); final TextEditingController _companyNameController = TextEditingController(); final FirebaseAuth auth = FirebaseAuth.instance; @override Widget build(BuildContext context) { String docId; docId = emailController.text; final User? user = auth.currentUser; double w = MediaQuery.of(context).size.width; double h = MediaQuery.of(context).size.height; return Scaffold( resizeToAvoidBottomInset: false, backgroundColor: Colors.white, body: Column( children: [ Container( width: w, height: h * 0.27, decoration: const BoxDecoration( image: DecorationImage( image: AssetImage("assets/loginsignupheader.png"), fit: BoxFit.fitWidth, ), ), ), Container( margin: const EdgeInsets.only(left: 30, right: 20), width: w, child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ const Text( 'Sign up for an account', style: TextStyle(fontSize: 25, color: Colors.grey), ), const SizedBox(height: 35), Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(30), boxShadow: [ BoxShadow( blurRadius: 10, spreadRadius: 7, offset: const Offset(1, 1), color: Colors.grey.withOpacity(0.2)) ]), child: TextField( controller: _usernameController, decoration: InputDecoration( hintText: 'Username', prefixIcon: const Icon(Icons.person), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(30), borderSide: const BorderSide( color: Colors.white, width: 1.0)), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(30), borderSide: const BorderSide( color: Colors.white, width: 1.0)), border: OutlineInputBorder( borderRadius: BorderRadius.circular(30), ), ), ), ), const SizedBox(height: 35), Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(30), boxShadow: [ BoxShadow( blurRadius: 10, spreadRadius: 7, offset: const Offset(1, 1), color: Colors.grey.withOpacity(0.2)) ]), child: TextField( controller: _companyNameController, decoration: InputDecoration( hintText: 'Company Name', prefixIcon: const Icon(Icons.business_center), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(30), borderSide: const BorderSide( color: Colors.white, width: 1.0)), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(30), borderSide: const BorderSide( color: Colors.white, width: 1.0)), border: OutlineInputBorder( borderRadius: BorderRadius.circular(30), ), ), ), ), const SizedBox(height: 35), Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(30), boxShadow: [ BoxShadow( blurRadius: 10, spreadRadius: 7, offset: const Offset(1, 1), color: Colors.grey.withOpacity(0.2)) ]), child: TextField( controller: _phoneNumberController, decoration: InputDecoration( hintText: 'Phone Number', prefixIcon: const Icon(Icons.phone), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(30), borderSide: const BorderSide( color: Colors.white, width: 1.0)), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(30), borderSide: const BorderSide( color: Colors.white, width: 1.0)), border: OutlineInputBorder( borderRadius: BorderRadius.circular(30), ), ), ), ), const SizedBox(height: 35), Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(30), boxShadow: [ BoxShadow( blurRadius: 10, spreadRadius: 7, offset: const Offset(1, 1), color: Colors.grey.withOpacity(0.2)) ]), child: TextField( controller: emailController, decoration: InputDecoration( hintText: 'Email', prefixIcon: const Icon(Icons.email_outlined), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(30), borderSide: const BorderSide( color: Colors.white, width: 1.0)), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(30), borderSide: const BorderSide( color: Colors.white, width: 1.0)), border: OutlineInputBorder( borderRadius: BorderRadius.circular(30), ), ), ), ), const SizedBox(height: 35), Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(30), boxShadow: [ BoxShadow( blurRadius: 10, spreadRadius: 7, offset: const Offset(1, 1), color: Colors.grey.withOpacity(0.2)) ]), child: TextField( controller: passwordController, obscureText: true, decoration: InputDecoration( hintText: 'Password', prefixIcon: const Icon(Icons.password), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(30), borderSide: const BorderSide( color: Colors.white, width: 1.0)), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(30), borderSide: const BorderSide( color: Colors.white, width: 1.0)), border: OutlineInputBorder( borderRadius: BorderRadius.circular(30), ), ), ), ), ], ), ), const SizedBox( height: 50, ), GestureDetector( onTap: () async { AuthController.instance.register( emailController.text.trim(), passwordController.text.trim()); FirebaseFirestore.instance.collection('users').doc(docId).set({ 'username': _usernameController.text, 'phone': _phoneNumberController.text, 'company_name': _companyNameController.text, 'email': emailController.text }); }, child: Container( width: w *.5, height: h *.06, decoration: BoxDecoration( borderRadius: BorderRadius.circular(30), image: const DecorationImage( image: AssetImage("assets/button.png"), fit: BoxFit.cover, ), ), child: const Center( child: Text( 'Sign Up', style: TextStyle( fontSize: 30, fontWeight: FontWeight.bold, color: Colors.white), ), )), ), SizedBox(height: w * 0.1), RichText( text: TextSpan( text: "Already have an account?", style: const TextStyle(color: Colors.grey, fontSize: 20), children: [ TextSpan( text: " Login", style: const TextStyle( color: Colors.grey, fontSize: 20, fontWeight: FontWeight.bold), recognizer: TapGestureRecognizer()..onTap = () { Navigator.push( context, MaterialPageRoute( builder: (context) => const Login())); }), ])), ], ), ); } }

account.dart - this is the page I want to display my Firestore data on account.dart - 这是我要在其上显示 Firestore 数据的页面

 class Account extends StatefulWidget { const Account({Key? key}): super(key: key); @override State<Account> createState() => _AccountState(); } class _AccountState extends State<Account> { @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.grey.shade50, body: Stack( fit: StackFit.expand, children: [ SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ const SizedBox(height: 10), const Text( 'Account Settings & Info', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: Colors.black), ), Card( elevation: 2.0, margin: const EdgeInsets.fromLTRB(16, 8.0, 16, 16.0), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10)), child: Column( children: <Widget>[ const SizedBox(height: 20), Container( width: 75, height: 75, decoration: BoxDecoration( color: Colors.grey[200], borderRadius: BorderRadius.circular(15), image: const DecorationImage(image: AssetImage('assets/tclogotransparent.png'), fit: BoxFit.cover) ), ), const SizedBox(height: 20), const BuildDivider(), ListTile( leading: const Icon( Icons.person, color: Colors.black, ), title: Text('Username: $username'), trailing: const Icon(Icons.keyboard_arrow_right), onTap: () { Navigator.push(context, MaterialPageRoute(builder: (context) => const ChangeEmail())); }, ), const BuildDivider(), ListTile( leading: const Icon( Icons.business_center, color: Colors.black, ), title: Text('Company Name: $companyName'), trailing: const Icon(Icons.keyboard_arrow_right), onTap: () { Navigator.push(context, MaterialPageRoute(builder: (context) => const ChangeEmail())); },), const BuildDivider(), ListTile( leading: const Icon( Icons.phone, color: Colors.black, ), title: Text('Phone Number: $phoneNumber'), trailing: const Icon(Icons.keyboard_arrow_right), onTap: () { Navigator.push(context, MaterialPageRoute(builder: (context) => const ChangeEmail())); }, ), const BuildDivider(), ListTile( leading: const Icon( Icons.email_outlined, color: Colors.black, ), title: Text('E-Mail: $emailAddress'), trailing: const Icon(Icons.keyboard_arrow_right), onTap: () { Navigator.push(context, MaterialPageRoute(builder: (context) => const ChangeEmail())); }, ), const BuildDivider(), ListTile( leading: const Icon( Icons.key, color: Colors.black, ), title: const Text('Change Password'), trailing: const Icon(Icons.keyboard_arrow_right), onTap: () { Navigator.push(context, MaterialPageRoute(builder: (context) => const ChangePassword())); }, ), const BuildDivider(), ListTile( leading: const Icon( Icons.upload, color: Colors.black, ), title: const Text('Upload Profile Picture'), trailing: const Icon(Icons.keyboard_arrow_right), onTap: () { }, ), ], ), ), Card( color: Colors.red[50], elevation: 2.0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10)), margin: const EdgeInsets.all(16), child: ListTile( onTap: () { AuthController.instance.signOut(); }, title: const Text('Log Out', style: TextStyle(fontWeight: FontWeight.bold, color: Colors.red),), leading: const Icon(Icons.logout_outlined, color: Colors.red) ), ), ], ), ), ], ), ); } }

Firestore Docs - I want to take this data and display it in the account page shown below Firestore Docs - 我想获取这些数据并将其显示在如下所示的帐户页面中

Edit: I have the document ids being set as the users email, I wanted to try an easy way to recall the document per account.编辑:我将文档 ID 设置为用户 email,我想尝试一种简单的方法来调用每个帐户的文档。 If this is wrong please let me know.如果这是错误的,请告诉我。

https://i.stack.imgur.com/53TOS.png https://i.stack.imgur.com/53TOS.png

Account Page - These are the fields I want to fill with the data, they all say N/A because I have a separate temporary file that uses constants to set those values帐户页面 - 这些是我想用数据填充的字段,它们都说 N/A 因为我有一个单独的临时文件,它使用常量来设置这些值

https://i.stack.imgur.com/eoHUE.png https://i.stack.imgur.com/eoHUE.png

Edit: Edited account.dart throws a _CastError编辑:已编辑帐户。dart 抛出 _CastError

https://i.stack.imgur.com/YRRz9.png https://i.stack.imgur.com/YRRz9.png

Make your account.dart a stateless widget, and try this code:-将您的account.dart设为无状态小部件,然后尝试以下代码:-

var user;

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

init()async{
user = ((await FirebaseFirestore.instance.collection("users")
                .doc(currentUser.email)
                .get())
            .data() as Map<String, dynamic>)['username'];
}

I have figured out the solution to my issue.我已经找到了解决我的问题的方法。 In the _AccountState class I added the following lines of code and it seemed to work for me.在 _AccountState class 我添加了以下代码行,它似乎对我有用。

I added this above the _AccountState class..我在 _AccountState class 上方添加了这个。

final FirebaseAuth _firebaseAuth = FirebaseAuth.instance

then inside the class I added this code above the build widget..然后在 class 中,我在构建小部件上方添加了此代码..

      void _getData() async {
    User? user = _firebaseAuth.currentUser;
    FirebaseFirestore.instance.collection('users').doc(user?.email).snapshots().listen((userData) {
      setState(() {
        username = userData.data()!['username'];
        companyName = userData.data()!['company_name'];
        phoneNumber = userData.data()!['phone'];
        emailAddress = userData.data()!['email'];
      });
    });
  }

  @override


void initState() {
    super.initState();
    _getData();
  }

After adding that into the state I just declared each variable in the title of my ListTiles and it seemed to work将其添加到 state 后,我刚刚在我的 ListTiles 标题中声明了每个变量,它似乎有效

ListTile(
   leading: const Icon(
     Icons.person,
     color: Colors.black,
   ),
   title: Text("Username: $username"),
   trailing: const Icon(Icons.keyboard_arrow_right),
   onTap: () {},
   ),

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

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