无法在Flutter中构建自定义小部件

5

我正在尝试在个人资料页面上呈现用户创建的帖子。这些帖子存储在Firestore中。我已经在post.dart中制作了一个帖子小部件以及帖子模型。但是这个帖子小部件没有生成。

profile.dart具有生成帖子的以下代码。

   class Profile extends StatefulWidget {
     final String profileId;
   
     Profile({this.profileId});
   
     @override
     _ProfileState createState() => _ProfileState();
   }
   
   class _ProfileState extends State<Profile> {
     bool isLoading = false;
     int postCount = 0;
     List<Post> posts = [];
     final String currentUserId = currentUser?.id;
   
     @override
     void initState() {
       super.initState();
       getProfilePosts();
     }
     getProfilePosts() async {
       setState(() {
         isLoading=true;
       });
       QuerySnapshot snapshot= await userPostRef
         .document(widget.profileId)
         .collection('userPosts')
         .getDocuments();
   
       setState(() {
         isLoading=false;
         postCount=snapshot.documents.length;
         posts=snapshot.documents.map((doc) =>Post.fromDocument(doc)).toList();
       });    
     }
   buildProfilePosts(){
       if(isLoading){
         return circularProgress();
       }
       return Column(children:posts);
    
     }
   
     @override
     Widget build(context) {
       return Scaffold(
         appBar: header(context, titleText: "Profile"),
         body: ListView(children: <Widget>[
           buildProfileHeader(),
           Divider(
             height: 0.0,
           ),
           buildProfilePosts(),
         ]),
       );
     }
   }

以下是包含帖子模型和帖子小部件的post.dart文件。

    class Post extends StatefulWidget {
      final String bucketId;
      final String postId;
      final String userId;
      final String username;
      final String post;
      final dynamic likes;
      final dynamic contributers;
      final String photoUrl;
    
      Post({
        this.bucketId,
        this.postId,
        this.userId,
        this.username,
        this.post,
        this.likes,
        this.contributers,
        this.photoUrl,
      });
    
      factory Post.fromDocument(DocumentSnapshot doc) {
        return Post(
          postId: doc['postId'],
          userId: doc['userId'],
          bucketId: doc['bucketId'],
          username: doc['username'],
          post: doc['post'],
          contributers: doc['contributers'],
          likes: doc['likes'],
          photoUrl: doc['photoUrl'],
        );
      }
    
      
     @override
      _PostState createState() => _PostState(
            postId: this.postId,
            bucketId: this.bucketId,
            userId: this.userId,
            username: this.username,
            post: this.post,
            likes: this.likes,
            contributers: this.contributers,
            likeCount: getLikeCount(this.likes),
            photoUrl: this.photoUrl,
          );
    }
    
    class _PostState extends State<Post> {
      final String currentUserId=currentUser?.id;
      final String bucketId;
      final String postId;
      final String userId;
      final String username;
      final String post;
      final String photoUrl;
      Map likes;
      Map contributers;
      int likeCount;
    
      _PostState({
        this.bucketId,
        this.postId,
        this.userId,
        this.username,
        this.post,
        this.likes,
        this.contributers,
        this.likeCount,
        this.photoUrl,
      });
    
      buildPostHeader(){
        return FutureBuilder(
          future: usersRef.document(userId).get(),
          builder: (context,snapshot){
            if(!snapshot.hasData){
              return circularProgress();
            }
            User user=User.fromDocument(snapshot.data);
            bool isPostOwner = currentUserId==userId;
            return ListTile(
              leading: CircleAvatar(
                backgroundImage: CachedNetworkImageProvider(user.photoUrl),
                backgroundColor: Colors.grey,
              ),
              title: GestureDetector(
                onTap: ()=> print('showing profile'),
                child: Text(
                  user.displayName,
                  style: TextStyle(
                    color: Colors.black,
                    fontWeight: FontWeight.bold
                  ),
                ),
              ),
              subtitle: Text(
                  "@"+user.username,
                  style: TextStyle(
                    color: Colors.grey,
                    fontWeight: FontWeight.normal
                  ),
               ),
               trailing: isPostOwner ? IconButton(
                 onPressed: ()=>handleDeletePost(context),
                 icon: Icon(Icons.more_vert),
               ):Text(''),
               
               );
          }
        
        );
      }
    
     
      buildPostBody(){
        return GestureDetector(
          onTap: ()=>print('go to bucket'),
          child: Stack(
            alignment: Alignment.center,
            children: <Widget>[
              Card(
                child: Text(
                  post,
                ),
              ),
            ],
          ),
        );
      }
    
      buildPostFooter(){
        return Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: <Widget>[
                Padding(padding: EdgeInsets.only(top: 40.0, left: 20.0)),
                Row(
                  children: <Widget>[
                    GestureDetector (
                      onTap: () => print('liking post'),
                      child: Icon(
                                Icons.favorite_border,
                                size: 28.0,
                                color: Colors.pink,
                              ),
                    ),
                    Text(
                      likeCount.toString(),
                    ),
    
                  ],
                ),
                Padding(padding: EdgeInsets.only(right: 20.0)),
                GestureDetector(
                  onTap: () => print('showing comments'),
                  child: Icon(
                    Icons.chat,
                    size: 28.0,
                    color: Colors.blue[900],
                  ),
                ),
              ],
        );
      }
      
    
      @override
      Widget build(BuildContext context) {
                print("Building widget");
        return Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
             buildPostHeader(),
    
              buildPostBody(),
              buildPostFooter(),
          ],
    
        );
      }
    }


调试控制台显示以下错误。

    Restarted application in 1,647ms.
    
    ════════ Exception caught by widgets library ═══════════════════════════════════
    The following _TypeError was thrown building NotificationListener<KeepAliveNotification>:
    type 'List<Object?>' is not a subtype of type 'Map<dynamic, dynamic>'
    
    The relevant error-causing widget was
    ListView
    When the exception was thrown, this was the stack
    #0      Post.createState
    #1      new StatefulElement
    #2      StatefulWidget.createElement
    #3      Element.inflateWidget
    #4      MultiChildRenderObjectElement.inflateWidget
    ...
    ════════════════════════════════════════════════════════════════════════════════
    
    ════════ Exception caught by widgets library ═══════════════════════════════════
    'package:flutter/src/rendering/sliver_multi_box_adaptor.dart': Failed assertion: line 258 pos 16: 'child == null || indexOf(child) > index': is not true.
    The relevant error-causing widget was
    ListView
    ════════════════════════════════════════════════════════════════════════════════
    
    ════════ Exception caught by widgets library ═══════════════════════════════════
    A RenderSliverPadding expected a child of type RenderSliver but received a child of type RenderErrorBox.
    The relevant error-causing widget was
    ListView
    ════════════════════════════════════════════════════════════════════════════════
    
    ════════ Exception caught by widgets library ═══════════════════════════════════
    'package:flutter/src/widgets/framework.dart': Failed assertion: line 4269 pos 14: 'owner!._debugCurrentBuildTarget == this': is not true.
    The relevant error-causing widget was
    ListView
    ════════════════════════════════════════════════════════════════════════════════
    
    ════════ Exception caught by widgets library ═══════════════════════════════════
    'package:flutter/src/widgets/framework.dart': Failed assertion: line 4269 pos 14: 'owner!._debugCurrentBuildTarget == this': is not true.
    The relevant error-causing widget was
    ListView
    ════════════════════════════════════════════════════════════════════════════════
    
    ════════ Exception caught by widgets library ═══════════════════════════════════
    'package:flutter/src/widgets/framework.dart': Failed assertion: line 4269 pos 14: 'owner!._debugCurrentBuildTarget == this': is not true.
    The relevant error-causing widget was
    ListView
    ════════════════════════════════════════════════════════════════════════════════
    
    ════════ Exception caught by widgets library ═══════════════════════════════════
    'package:flutter/src/widgets/framework.dart': Failed assertion: line 4269 pos 14: 'owner!._debugCurrentBuildTarget == this': is not true.
    The relevant error-causing widget was
    ListView
    ════════════════════════════════════════════════════════════════════════════════
    
    ════════ Exception caught by widgets library ═══════════════════════════════════
    'package:flutter/src/widgets/framework.dart': Failed assertion: line 4269 pos 14: 'owner!._debugCurrentBuildTarget == this': is not true.
    The relevant error-causing widget was
    ListView
    ════════════════════════════════════════════════════════════════════════════════
    
    ════════ Exception caught by widgets library ═══════════════════════════════════
    'package:flutter/src/widgets/framework.dart': Failed assertion: line 4269 pos 14: 'owner!._debugCurrentBuildTarget == this': is not true.
    The relevant error-causing widget was
    ListView
    ════════════════════════════════════════════════════════════════════════════════
    
    ════════ Exception caught by widgets library ═══════════════════════════════════
    'package:flutter/src/widgets/framework.dart': Failed assertion: line 4269 pos 14: 'owner!._debugCurrentBuildTarget == this': is not true.
    The relevant error-causing widget was
    Scaffold
    ════════════════════════════════════════════════════════════════════════════════
    
    ════════ Exception caught by widgets library ═══════════════════════════════════
    'package:flutter/src/widgets/framework.dart': Failed assertion: line 4269 pos 14: 'owner!._debugCurrentBuildTarget == this': is not true.
    The relevant error-causing widget was
    Scaffold
    ════════════════════════════════════════════════════════════════════════════════
    
    ════════ Exception caught by widgets library ═══════════════════════════════════
    'package:flutter/src/widgets/framework.dart': Failed assertion: line 4269 pos 14: 'owner!._debugCurrentBuildTarget == this': is not true.
    The relevant error-causing widget was
    Scaffold
    ════════════════════════════════════════════════════════════════════════════════
    
    ════════ Exception caught by widgets library ═══════════════════════════════════
    'package:flutter/src/widgets/framework.dart': Failed assertion: line 4269 pos 14: 'owner!._debugCurrentBuildTarget == this': is not true.
    The relevant error-causing widget was
    Scaffold
    ════════════════════════════════════════════════════════════════════════════════
    
    ════════ Exception caught by widgets library ═══════════════════════════════════
    'package:flutter/src/widgets/framework.dart': Failed assertion: line 4269 pos 14: 'owner!._debugCurrentBuildTarget == this': is not true.
    The relevant error-causing widget was
    Scaffold
    ════════════════════════════════════════════════════════════════════════════════
    
    ════════ Exception caught by widgets library ═══════════════════════════════════
    'package:flutter/src/widgets/framework.dart': Failed assertion: line 4269 pos 14: 'owner!._debugCurrentBuildTarget == this': is not true.
    The relevant error-causing widget was
    Scaffold
    ════════════════════════════════════════════════════════════════════════════════
    
    ════════ Exception caught by widgets library ═══════════════════════════════════
    'package:flutter/src/widgets/framework.dart': Failed assertion: line 4269 pos 14: 'owner!._debugCurrentBuildTarget == this': is not true.
    The relevant error-causing widget was
    Scaffold
    ════════════════════════════════════════════════════════════════════════════════
    
    ════════ Exception caught by widgets library ═══════════════════════════════════
    'package:flutter/src/widgets/framework.dart': Failed assertion: line 4269 pos 14: 'owner!._debugCurrentBuildTarget == this': is not true.
    The relevant error-causing widget was
    Scaffold
    ════════════════════════════════════════════════════════════════════════════════
    
    ════════ Exception caught by widgets library ═══════════════════════════════════
    'package:flutter/src/widgets/framework.dart': Failed assertion: line 4269 pos 14: 'owner!._debugCurrentBuildTarget == this': is not true.
    The relevant error-causing widget was
    Scaffold
    ════════════════════════════════════════════════════════════════════════════════
    
    ════════ Exception caught by widgets library ═══════════════════════════════════
    'package:flutter/src/widgets/framework.dart': Failed assertion: line 4269 pos 14: 'owner!._debugCurrentBuildTarget == this': is not true.
    The relevant error-causing widget was
    Scaffold
    ════════════════════════════════════════════════════════════════════════════════
    
    ════════ Exception caught by widgets library ═══════════════════════════════════
    'package:flutter/src/widgets/framework.dart': Failed assertion: line 4269 pos 14: 'owner!._debugCurrentBuildTarget == this': is not true.
    The relevant error-causing widget was
    Scaffold
    ════════════════════════════════════════════════════════════════════════════════
    
    ════════ Exception caught by widgets library ═══════════════════════════════════
    'package:flutter/src/widgets/framework.dart': Failed assertion: line 4269 pos 14: 'owner!._debugCurrentBuildTarget == this': is not true.
    The relevant error-causing widget was
    Profile
    ════════════════════════════════════════════════════════════════════════════════
    
    ════════ Exception caught by widgets library ═══════════════════════════════════
    'package:flutter/src/widgets/framework.dart': Failed assertion: line 4269 pos 14: 'owner!._debugCurrentBuildTarget == this': is not true.
    The relevant error-causing widget was
    Profile
    ════════════════════════════════════════════════════════════════════════════════

就我个人而言,过度依赖类型推断通常会导致更加晦涩的错误信息。我不知道这是否有所帮助,但是动态类型可能意味着类型无法可靠地推断。您可以尝试为函数添加返回类型,看看是否能获得更清晰的错误消息。例如:Widget buildPostFooter(){...} - Pat9RB
已将返回值小部件添加到函数中,但仍显示相同的错误。 - Ayush Saxena
1
Map likesMap contributers都是Map<dynamic,dynamic>类型(因为在声明中没有指定类型)。您是否检查过DocumentSnapshot['contributers']DocumentSnapshot['likes']是否为Map(而不是List)? - Pat9RB
是的,那就是问题所在。谢谢。 - Ayush Saxena
请查看此答案。https://stackoverflow.com/a/68465876/6813907 - Sajjad
嘿@AyushSaxena,有更新吗...试着检查一下我的答案,很可能会对你有用。 - Mithson
3个回答

2
有太多事情需要处理。请简化您的示例。由于缺少依赖项(例如 User 类),我无法复制和执行代码。
代码非常混乱,您在各个地方混合了视图逻辑、应用程序逻辑、模型和视图模型,这使得很难理解出现异常的原因和位置。此外,您使用 Map,因为 Firestore 返回这些类型的数据。相反,您应该将动态的 Map 转换为自己的(视图)模型类。这样,编译器可以更好地解释出错的原因。
问题可能与您声明为 dynamic 的属性有关("likes" 和 "contributers")。您是否尝试过调试它们是否真的是 Map 而不是 List?因为在 Post 构造函数中,您将它们声明为 dynamic,而在 PostState 中,您期望 Map
您能否至少将问题缩小到一个小部件?当您不渲染标题和页脚时,问题是否仍然存在?

1

profile.dart

getProfilePosts() async {
    setState(() {
      isLoading=true;
    });
    QuerySnapshot snapshot= await userPostRef
      .document(widget.profileId)
      .collection('userPosts')
      .getDocuments();

    setState(() {
      isLoading=false;
      postCount=snapshot.documents.length;
      posts=snapshot.documents.map((doc){
          Post.fromDocument(doc)
      }).toList();
    });    
}

在 post.dart 文件中,将工厂方法更改为以下内容。
factory Post.fromDocument(DocumentSnapshot document) {
         Map<String, dynamic> doc = document.data()! as Map<String, dynamic>;
        return Post(
          postId: doc['postId'],
          userId: doc['userId'],
          bucketId: doc['bucketId'],
          username: doc['username'],
          post: doc['post'],
          contributers: doc['contributers'],
          likes: doc['likes'],
          photoUrl: doc['photoUrl'],
        );
      }

尝试这个。

你是指 value.data() 代表 doc.data() 吗? - Ayush Saxena
同时,Post.fromDocument需要一个DocumentSnapshot作为参数。 - Ayush Saxena
是的,那是文档。抱歉,我的错。好的,我会检查并更新答案。 - Swaroop Maddu

0

尝试这些更改:

将您的代码从

posts=snapshot.documents.map((doc) =>Post.fromDocument(doc)).toList()

,

posts=snapshot.documents.map((doc) =>Post.fromDocument(doc))

由于Firestore已经为您的请求返回了对象列表,并且您再次将其转换为列表,因此可能会导致错误。 因此,删除您的.toList()方法应该解决错误

首先尝试使用上述更改运行,如果没有成功,则继续进行以下更改:

然后尝试在setState之外删除postspostCount,并运行您的项目,这可能会解决错误

此外,您应该在代码中使用asyncawait来从Firestore获取数据,否则获取的数据将不完整

有关QuerySnapshot的更多信息,请参见此处:

QuerySnapshot返回什么? 返回自上次快照以来更改的文档列表。如果这是第一个快照,则所有文档都将作为添加更改出现在列表中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接