当键盘在颤音中底部的底纸内部移动Textfield

发布于 2025-01-23 07:52:58 字数 8704 浏览 3 评论 0原文

我目前正在尝试创建某种Tiktok,例如Flutter中的评论部分。为此,我使用的是ModalBottomSheet和扩展的ListView,其中包含内部注释。但是,我未能归档我的Textfield在选择并出现键盘时会向上移动,这意味着我在选择后总是再看不到Textfield。我已经尝试使用FocusNode和Animation Controller,但是由于包含评论的Flex容器,它没有奏效...我知道这是很多代码,但请帮助我真的无法弄清楚。

底部表小部件:

void onCommentButtonPressed() {
    showModalBottomSheet(
      context: context,
      isScrollControlled: true,
      backgroundColor: Colors.transparent,
      builder: (context) => Container(
        height: MediaQuery.of(context).size.height * 0.75,
        decoration: new BoxDecoration(
          color: Colors.grey[900],
          borderRadius: new BorderRadius.only(
            topLeft: const Radius.circular(20.0),
            topRight: const Radius.circular(20.0),
          ),
        ),
        child: Column(
          children: <Widget>[
            Comments(
              postId: targetId,
              postOwnerId: ownerId,
            ),
          ],
        ),
      ),
    );
  }

其中的评论部分:

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app/Widgets/Images/profile_picture_small.dart';
import 'package:flutter_app/Widgets/header.dart';
import 'package:flutter_app/Widgets/progress.dart';
import 'package:flutter_app/constants.dart';
import 'package:provider/provider.dart';
import '../../Screens/Authenticate/authservice.dart';
import '../../Screens/Authenticate/database.dart';
import '../../models/user.dart';
import 'package:timeago/timeago.dart' as timeago;

class Comments extends StatefulWidget {
  final String postId;
  final String postOwnerId;

  Comments({
    required this.postId,
    required this.postOwnerId,
  });

  @override
  CommentsState createState() => CommentsState(
    postId: postId,
    postOwnerId: postOwnerId,
  );
}

class CommentsState extends State<Comments> {
  TextEditingController commentController = TextEditingController();
  final String postId;
  final String postOwnerId;

  CommentsState({
    required this.postId,
    required this.postOwnerId,
  });


  @override
  Widget build(BuildContext context) {
    return Flexible(
      child: Column(
            children: [
              Expanded(
                child: buildComments(),
              ),
              buildTextField(),
            ],
      ),
    );
  }

  addComment(){
    final currentUser = Provider.of<MyUser>(context, listen: false);
    bool isNotPostOwner = postOwnerId != currentUser.id;

    commentsRef.doc(postId).collection('comments').add({
      'username': currentUser.username,
      'comment': commentController.text,
      'timestamp': DateTime.now(),
      'avatarUrl': currentUser.photoUrl,
      'userId': currentUser.id,
    });

    if(isNotPostOwner) {
      activityFeedRef.doc(postOwnerId).collection('feedItems').add({
        'type': 'comment',
        'commentData': commentController.text,
        'username': currentUser.username,
        'userId': currentUser.id,
        'userProfileImg': currentUser.photoUrl,
        'postId': postId,
        'timestamp': timestamp,
      });
    }
    commentController.clear();
  }

  buildComments() {
    return StreamBuilder<QuerySnapshot>(
      stream: commentsRef.
      doc(postId).
      collection('comments').
      orderBy('timestamp', descending: true).
      snapshots(),
      builder: (context, snapshot){
        if (!snapshot.hasData){
          return circularProgress();
        }
        else {
          List<Comment> comments = [];
          snapshot.data!.docs.forEach((doc){
            comments.add(Comment.fromDocument(doc));
          });
          return ListView(children: comments,);
        }
      },
    );
  }

  Widget buildTextField() {
    return Container(
      padding: EdgeInsets.symmetric(
        vertical: kDefaultPadding / 2,
        horizontal: kDefaultPadding / 2,
      ),
      decoration: BoxDecoration(
        color: Colors.transparent,
        boxShadow: [
          BoxShadow(
            offset: Offset(0, 4),
            blurRadius: 32,
            color: Colors.blueGrey.withOpacity(0.1),
          ),
        ],
      ),
      child: SafeArea(
        child: Row(
          children: [
            ProfilePictureSmall(),
            Padding(padding: EdgeInsets.symmetric(horizontal: 5)),
            Expanded(
              child: Container(
                padding: EdgeInsets.symmetric(
                  horizontal: kDefaultPadding * 0.75,
                ),
                decoration: BoxDecoration(
                  color: Colors.grey[800],
                  borderRadius: BorderRadius.circular(40),
                ),
                child: Row(
                  children: [
                    SizedBox(width: kDefaultPadding / 4),
                    Expanded(
                      child: TextField(
                        controller: commentController,
                        decoration: InputDecoration(
                          hintText: "Write a comment...",
                          border: InputBorder.none,
                        ),
                      ),
                    ),
                    InkWell(
                      onTap: () => addComment(),
                      child: Container(
                        decoration: BoxDecoration(
                          color: Colors.grey,
                          borderRadius: BorderRadius.circular(40.0),
                        ),
                        child: Padding(
                          padding: const EdgeInsets.all(5.0),
                          child: Icon(
                            Icons.arrow_upward_rounded,
                            color: Theme.of(context)
                                .textTheme
                                .bodyText1!
                                .color!
                                .withOpacity(0.64),
                          ),
                        ),
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class Comment extends StatelessWidget {
  final String username;
  final String userId;
  final String avatarUrl;
  final String comment;
  final Timestamp timestamp;

  Comment({
    required this.username,
    required this.userId,
    required this.avatarUrl,
    required this.comment,
    required this.timestamp,
});

  factory Comment.fromDocument(DocumentSnapshot doc){
    return Comment(
      username: doc['username'],
      userId: doc['userId'],
      comment: doc['comment'],
      timestamp: doc['timestamp'],
      avatarUrl: doc['avatarUrl'],
    );
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        ListTile(
          title: RichText(
              text: TextSpan(text: '@...$username  ',
                style: TextStyle(
                color: Colors.white,
                fontWeight: FontWeight.bold,
              ),
              children: <TextSpan> [
                TextSpan(text: '$comment',
                  style: Theme.of(context).textTheme.bodyText2),
              ]
              ),
          ),
          leading: ProfilePictureSmall(),
          subtitle: RichText(
            text: TextSpan(
                style: TextStyle(
                  fontSize: 12,
                  color: Colors.white,
                  fontWeight: FontWeight.bold,
                ),
                children: <TextSpan> [
                  TextSpan(text: '${timeago.format(timestamp.toDate(), locale: 'en_short')}     ',
                    style: TextStyle(
                        color: Colors.grey[400],
                        fontWeight: FontWeight.w400,
                    ),),
                  TextSpan(text: '193 Rockets     ',
                    style: TextStyle(
                        color: Colors.grey[400]
                    ),),
                  TextSpan(text: 'Reply',
                    style: TextStyle(
                        color: Colors.grey[400]
                    ),
                  ),
                ]
            ),
          ),
          trailing: buildCommentFooter(context),
        ),
        // Divider(color: Colors.white,),
      ],
    );
  }

  buildCommentFooter(BuildContext context){
    return Column(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: [
        GestureDetector(
          onTap: ()=> print('pressed'),
          child: Icon(
            Icons.monetization_on_rounded,
            size: 20,
            color: Colors.grey,
          ),
        ),
      ],
    );
  }
}

I am currently trying to create some kind of TikTok like comment section in flutter. For this I'm using a ModalBottomSheet and a Expanded Listview with the comments inside. However, I'm failing to archive that my TextField moves up when its selected and the Keyboard appears, meaning I always cant see the Textfield anymore after it's selection. I already tried using a focusnode and animation controller, however it didnt work out because of the Flex container which contains the comments... I know it's much code but please help I really cant figure it out.

The BottomSheet Widget:

void onCommentButtonPressed() {
    showModalBottomSheet(
      context: context,
      isScrollControlled: true,
      backgroundColor: Colors.transparent,
      builder: (context) => Container(
        height: MediaQuery.of(context).size.height * 0.75,
        decoration: new BoxDecoration(
          color: Colors.grey[900],
          borderRadius: new BorderRadius.only(
            topLeft: const Radius.circular(20.0),
            topRight: const Radius.circular(20.0),
          ),
        ),
        child: Column(
          children: <Widget>[
            Comments(
              postId: targetId,
              postOwnerId: ownerId,
            ),
          ],
        ),
      ),
    );
  }

and the comment section inside of it:

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app/Widgets/Images/profile_picture_small.dart';
import 'package:flutter_app/Widgets/header.dart';
import 'package:flutter_app/Widgets/progress.dart';
import 'package:flutter_app/constants.dart';
import 'package:provider/provider.dart';
import '../../Screens/Authenticate/authservice.dart';
import '../../Screens/Authenticate/database.dart';
import '../../models/user.dart';
import 'package:timeago/timeago.dart' as timeago;

class Comments extends StatefulWidget {
  final String postId;
  final String postOwnerId;

  Comments({
    required this.postId,
    required this.postOwnerId,
  });

  @override
  CommentsState createState() => CommentsState(
    postId: postId,
    postOwnerId: postOwnerId,
  );
}

class CommentsState extends State<Comments> {
  TextEditingController commentController = TextEditingController();
  final String postId;
  final String postOwnerId;

  CommentsState({
    required this.postId,
    required this.postOwnerId,
  });


  @override
  Widget build(BuildContext context) {
    return Flexible(
      child: Column(
            children: [
              Expanded(
                child: buildComments(),
              ),
              buildTextField(),
            ],
      ),
    );
  }

  addComment(){
    final currentUser = Provider.of<MyUser>(context, listen: false);
    bool isNotPostOwner = postOwnerId != currentUser.id;

    commentsRef.doc(postId).collection('comments').add({
      'username': currentUser.username,
      'comment': commentController.text,
      'timestamp': DateTime.now(),
      'avatarUrl': currentUser.photoUrl,
      'userId': currentUser.id,
    });

    if(isNotPostOwner) {
      activityFeedRef.doc(postOwnerId).collection('feedItems').add({
        'type': 'comment',
        'commentData': commentController.text,
        'username': currentUser.username,
        'userId': currentUser.id,
        'userProfileImg': currentUser.photoUrl,
        'postId': postId,
        'timestamp': timestamp,
      });
    }
    commentController.clear();
  }

  buildComments() {
    return StreamBuilder<QuerySnapshot>(
      stream: commentsRef.
      doc(postId).
      collection('comments').
      orderBy('timestamp', descending: true).
      snapshots(),
      builder: (context, snapshot){
        if (!snapshot.hasData){
          return circularProgress();
        }
        else {
          List<Comment> comments = [];
          snapshot.data!.docs.forEach((doc){
            comments.add(Comment.fromDocument(doc));
          });
          return ListView(children: comments,);
        }
      },
    );
  }

  Widget buildTextField() {
    return Container(
      padding: EdgeInsets.symmetric(
        vertical: kDefaultPadding / 2,
        horizontal: kDefaultPadding / 2,
      ),
      decoration: BoxDecoration(
        color: Colors.transparent,
        boxShadow: [
          BoxShadow(
            offset: Offset(0, 4),
            blurRadius: 32,
            color: Colors.blueGrey.withOpacity(0.1),
          ),
        ],
      ),
      child: SafeArea(
        child: Row(
          children: [
            ProfilePictureSmall(),
            Padding(padding: EdgeInsets.symmetric(horizontal: 5)),
            Expanded(
              child: Container(
                padding: EdgeInsets.symmetric(
                  horizontal: kDefaultPadding * 0.75,
                ),
                decoration: BoxDecoration(
                  color: Colors.grey[800],
                  borderRadius: BorderRadius.circular(40),
                ),
                child: Row(
                  children: [
                    SizedBox(width: kDefaultPadding / 4),
                    Expanded(
                      child: TextField(
                        controller: commentController,
                        decoration: InputDecoration(
                          hintText: "Write a comment...",
                          border: InputBorder.none,
                        ),
                      ),
                    ),
                    InkWell(
                      onTap: () => addComment(),
                      child: Container(
                        decoration: BoxDecoration(
                          color: Colors.grey,
                          borderRadius: BorderRadius.circular(40.0),
                        ),
                        child: Padding(
                          padding: const EdgeInsets.all(5.0),
                          child: Icon(
                            Icons.arrow_upward_rounded,
                            color: Theme.of(context)
                                .textTheme
                                .bodyText1!
                                .color!
                                .withOpacity(0.64),
                          ),
                        ),
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class Comment extends StatelessWidget {
  final String username;
  final String userId;
  final String avatarUrl;
  final String comment;
  final Timestamp timestamp;

  Comment({
    required this.username,
    required this.userId,
    required this.avatarUrl,
    required this.comment,
    required this.timestamp,
});

  factory Comment.fromDocument(DocumentSnapshot doc){
    return Comment(
      username: doc['username'],
      userId: doc['userId'],
      comment: doc['comment'],
      timestamp: doc['timestamp'],
      avatarUrl: doc['avatarUrl'],
    );
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        ListTile(
          title: RichText(
              text: TextSpan(text: '@...$username  ',
                style: TextStyle(
                color: Colors.white,
                fontWeight: FontWeight.bold,
              ),
              children: <TextSpan> [
                TextSpan(text: '$comment',
                  style: Theme.of(context).textTheme.bodyText2),
              ]
              ),
          ),
          leading: ProfilePictureSmall(),
          subtitle: RichText(
            text: TextSpan(
                style: TextStyle(
                  fontSize: 12,
                  color: Colors.white,
                  fontWeight: FontWeight.bold,
                ),
                children: <TextSpan> [
                  TextSpan(text: '${timeago.format(timestamp.toDate(), locale: 'en_short')}     ',
                    style: TextStyle(
                        color: Colors.grey[400],
                        fontWeight: FontWeight.w400,
                    ),),
                  TextSpan(text: '193 Rockets     ',
                    style: TextStyle(
                        color: Colors.grey[400]
                    ),),
                  TextSpan(text: 'Reply',
                    style: TextStyle(
                        color: Colors.grey[400]
                    ),
                  ),
                ]
            ),
          ),
          trailing: buildCommentFooter(context),
        ),
        // Divider(color: Colors.white,),
      ],
    );
  }

  buildCommentFooter(BuildContext context){
    return Column(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: [
        GestureDetector(
          onTap: ()=> print('pressed'),
          child: Icon(
            Icons.monetization_on_rounded,
            size: 20,
            color: Colors.grey,
          ),
        ),
      ],
    );
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文