如何使底栏随键盘向上移动(颤动)

Posted

技术标签:

【中文标题】如何使底栏随键盘向上移动(颤动)【英文标题】:How to make the bottom bar move up with the keyboard (flutter) 【发布时间】:2021-03-03 09:15:21 【问题描述】:

我试图让我的聊天栏(文本字段、2 个按钮和文本字段后面的黑条)在使用时随键盘一起升起。

我尝试了以下方法:

    使用底部的定位小部件中的所有元素包装堆栈:MediaQuery.of(context).viewInsets.bottom, 但是,如果我这样做,它会摆脱 2 个按钮和黑条,并且在使用键盘时不会提升文本字段。

    使用底部填充堆栈:MediaQuery.of(context).viewInsets.bottom, 这会导致与上面 #1 中相同的不良结果

    将堆栈包装在单个子滚动视图中: Move textfield up when keyboard appears in Flutter 如果我将堆栈包装在 singlechildscrollview 中,则在使用键盘时它不会移动。

如果有人能引导我朝着正确的方向前进,也许我将它们包装在错误的小部件中,或者我必须使用动画来向上移动堆栈。

代码如下:

import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'main.dart';
import 'recurringwidgets/size_config.dart';



class ChatDemo extends StatefulWidget 


  ChatDemo();

  @override
  _ChatDemoState createState() => _ChatDemoState();


class _ChatDemoState extends State<ChatDemo> with RouteAware 

  double scrollMark;
  @override
  void initState() 
 
  

  void didChangeDependencies() 
    super.didChangeDependencies();
    routeObserver.subscribe(this, ModalRoute.of(context));
  

  @override
  void dispose() 
    routeObserver.unsubscribe(this);
    super.dispose();
  

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      backgroundColor: Colors.purple[300],
        resizeToAvoidBottomInset: false,
        //resizeToAvoidBottomPadding: true,

        body: SafeArea(
    bottom: false,
    top: false,
    child: //Column(
          //mainAxisAlignment: MainAxisAlignment.spaceAround,
          //children: <Widget>[

          Stack(
      children: <Widget>[
          
            //header(context, "Chat"),
            //EdgeInsets.fromLTRB(2.5, 184, 2.5, 126),
            //padding: EdgeInsets.only(top:105),
            GestureDetector(
              onTap: () => FocusScope.of(context).unfocus(),
              child: Container(
              ),
            ),
Positioned(
  
  child:   Padding(
    padding: EdgeInsets.only(top: 750 * SizeConfig.heightRatio,  ),
    child: SingleChildScrollView(
          child: Stack(
        children: [
  Positioned(
      top: 22.5 * SizeConfig.heightRatio,
      bottom: 0,
      child: ClipRRect(
        borderRadius: BorderRadius.only(
              topLeft: Radius.circular(32.0),
              topRight: Radius.circular(32.0),
        ),
        child: ClipRect(
              //clipBehavior: Clip.antiAlias,
              child: BackdropFilter(
                filter: ui.ImageFilter.blur(
                  sigmaX: 20,
                  sigmaY: 20,
                ),
                child: Transform.translate(
                  offset: Offset(0, 20 * SizeConfig.heightRatio),
                  child: Container(
                    constraints: BoxConstraints(
          maxHeight: 75,
          minHeight: 42,
                    ), //height: 42,
                    width: SizeConfig.screenWidth,
                    decoration: BoxDecoration(
          borderRadius: BorderRadius.only(
              topLeft: Radius.circular(32.0),
              topRight: Radius.circular(32.0),
          ),
          color:
                const Color(0xFF000000)//.withOpacity(0.00),
                    ),
                  ),
                ),
              ),
        ),
      ),
              ),
        Row(
               mainAxisSize: MainAxisSize.max,
               mainAxisAlignment: MainAxisAlignment.spaceAround,
        children:[
              Padding(
      padding: EdgeInsets.only(left:20.0,bottom: (10)),
      child: Container(
        decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(27.5),
        boxShadow: [
        BoxShadow(
      color: const Color(0x29000000),
      offset: Offset(3, 3),
      blurRadius: 6,
        ),
        ],
  ),
        child: CircleAvatar( ///radius 22
      backgroundColor: Color(0xffffffff),
      radius: 22,
      child: SvgPicture.string(
  _svg_nznkw8,
  allowDrawingOutsideViewBox: true,
  fit: BoxFit.fill,
              ),
  
              
        ),
      ),
              ),
  Flexible(
  flex:6,
        child: Container(
              
        ),
      ),
      Padding(
        padding: const EdgeInsets.only(right:20.0,bottom: 10),
        child: Container(
              decoration: BoxDecoration(
  borderRadius: BorderRadius.circular(27.5),
        boxShadow: [
        BoxShadow(
              color: const Color(0x29000000),
              offset: Offset(3, 3),
              blurRadius: 6,
        ),
        ],
        ),
              child: CircleAvatar( ///radius 22
              backgroundColor:Color(0xffffffff) ,
              radius: 22,
              child: SvgPicture.string(
  _svg_52blhh,
  allowDrawingOutsideViewBox: true,
  fit: BoxFit.fill,
              ),),
        ),
      ),
  
        ], 
        ),
         
        
        ],
        ),
    )
  ),
),

 Padding(
        padding: EdgeInsets.only(top:760*SizeConfig.heightRatio,left:60,),
        child: Container(
            //margin: EdgeInsets.only(top:760),
            child: ChatBubble()),
                  ),
      ],
    ),
          ),
      );
  


class ChatBubble extends StatefulWidget 
  const ChatBubble(
    Key key,
  ) : super(key: key);

  @override
  ChatBubbleState createState() => ChatBubbleState();


class ChatBubbleState extends State<ChatBubble> 
  @override
  Widget build(BuildContext context) 
    final TextEditingController myController = TextEditingController();
    //builds the bar
    return Padding(
      padding: const EdgeInsets.only(bottom: 10),
      child: Container(
        //margin: EdgeInsets.only(top:13,bottom: 5),
        //color: Colors.blue,
        /*constraints: BoxConstraints(
            maxHeight: 176,
          ),*/
        //height: chatBarHeight,
        constraints: BoxConstraints(
          maxHeight: 176,
          minHeight: 47.5, //52.5
        ),
        width: 240.0 * SizeConfig.widthRatio, ///310
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(27.5),
          //color: Colors.blue,
          color: const Color(0xffffffff),
          boxShadow: [
            BoxShadow(
              color: const Color(0x29000000),
              offset: Offset(3, 3),
              blurRadius: 6,
            ),
          ],
        ),
        child: Padding(
          padding: EdgeInsets.only(
              left: 12 * SizeConfig.widthRatio,
              right: 12 * SizeConfig.widthRatio,
              top: 13 * SizeConfig.heightRatio,
              bottom: 5 * SizeConfig.heightRatio),
          child: TextFormField(
            textAlign: TextAlign.start,
            style: TextStyle(
                fontSize: 17 ,
                color: const Color(0xd9343f4b),
                fontFamily: 'Lato'),
            //textAlign: TextAlign.left,
            maxLines: null,
            textCapitalization: TextCapitalization.sentences,
            controller: myController,
            decoration: InputDecoration.collapsed(
                hintStyle: TextStyle(
                  color: Color(0x80343f4b),
                  fontFamily: 'Lato',
                  fontSize: 15 ,
                  //color: const Color(0xd9343f4b),
                ),
                // hintStyle: ,
                hintText: 'Enter Comment'),
          ),
        ),
      ), //Padding
      //),
    );
  





const String _svg_52blhh = //send
    '<svg viewBox="332.0 762.0 20.0 20.0" ><path transform="translate(332.0, 762.0)" d="M 18.59535026550293 0.1261749565601349 L 0.4879408478736877 10.56938934326172 C -0.2191661894321442 10.97555732727051 -0.1293128132820129 11.95973491668701 0.5738875865936279 12.25654983520508 L 4.726676464080811 13.99838733673096 L 15.95053577423096 4.109749794006348 C 16.16540145874023 3.918381690979004 16.47012329101562 4.211291790008545 16.28650856018066 4.433903217315674 L 6.875344276428223 15.89644432067871 L 6.875344276428223 19.04034423828125 C 6.875344276428223 19.96203422546387 7.988744735717773 20.32524108886719 8.535677909851074 19.65740776062012 L 11.01641273498535 16.63848304748535 L 15.88412189483643 18.6771354675293 C 16.43886947631836 18.91146278381348 17.07174873352051 18.56387710571289 17.1733226776123 17.96634101867676 L 19.98612403869629 1.094730377197266 C 20.11895179748535 0.3058263659477234 19.27120399475098 -0.2643715739250183 18.59535026550293 0.1261749565601349 Z" fill="#343f4b" stroke="none" stroke- stroke-miterlimit="10" stroke-linecap="butt" /></svg>';
const String _svg_nznkw8 =
    '<svg viewBox="24.0 762.0 22.0 22.0" ><path transform="translate(24.0, 762.0)" d="M 20.4285717010498 8.642857551574707 L 13.35714244842529 8.642857551574707 L 13.35714244842529 1.571428537368774 C 13.35714244842529 0.703705370426178 12.65343761444092 0 11.7857141494751 0 L 10.2142858505249 0 C 9.346562385559082 0 8.642857551574707 0.703705370426178 8.642857551574707 1.571428537368774 L 8.642857551574707 8.642857551574707 L 1.571428537368774 8.642857551574707 C 0.703705370426178 8.642857551574707 0 9.346562385559082 0 10.2142858505249 L 0 11.7857141494751 C 0 12.65343761444092 0.703705370426178 13.35714244842529 1.571428537368774 13.35714244842529 L 8.642857551574707 13.35714244842529 L 8.642857551574707 20.4285717010498 C 8.642857551574707 21.29629516601562 9.346562385559082 22 10.2142858505249 22 L 11.7857141494751 22 C 12.65343761444092 22 13.35714244842529 21.29629516601562 13.35714244842529 20.4285717010498 L 13.35714244842529 13.35714244842529 L 20.4285717010498 13.35714244842529 C 21.29629516601562 13.35714244842529 22 12.65343761444092 22 11.7857141494751 L 22 10.2142858505249 C 22 9.346562385559082 21.29629516601562 8.642857551574707 20.4285717010498 8.642857551574707 Z" fill="#343f4b" stroke="none" stroke- stroke-miterlimit="10" stroke-linecap="butt" /></svg>';

【问题讨论】:

【参考方案1】:

首先你应该为你的SingleChildScrollView定义一个控制器

ScrollController _scrollController = new ScrollController();

然后将其定义为它的控制器

SingleChildScrollView(
        controller: _scrollController,

那么在TextField中就可以使用onTap函数了

Form(
              child: TextFormField(
                onTap: () 
                  _scrollController
                      .jumpTo(_scrollController.position.maxScrollExtent);
                ,
                onSaved: (str) ,
                keyboardType: TextInputType.emailAddress,
                decoration: InputDecoration(
                  labelText: 'Email Address',
                  hintText: 'you@example.com',
                ),
              ),
            ),

每当用户点击文本字段屏幕跳到底部时使用代码 你也可以用这个代码而不是那个来动画它

onTap:()
 _scrollController.animateTo(_scrollController.position.maxScrollExtent, duration: Duration(milliseconds: 500), curve: Curves.fastOutSlowIn);       

【讨论】:

您好,我编辑了问题以澄清我的问题。为了清楚起见,我试图让聊天栏随着键盘上升。 每当用户点击文本字段并想写点什么,对吧? 我已经更新了我的代码,尝试一下并告诉我结果 我也没有运气,因为你在指定包装单个子滚动视图的位置,我将它包装在几乎每个小部件中,但没有得到预期的结果

以上是关于如何使底栏随键盘向上移动(颤动)的主要内容,如果未能解决你的问题,请参考以下文章

在 iPad 上,如何防止模态视图在键盘呈现时向上移动?

当使用 Swift 出现键盘时如何向上移动 UIViewController 的内容

键盘存在时 UIViewController 向上移动

如何在键盘外观上向上移动包括pickerview在内的整个视图

如何防止在android中打开键盘时反应本机模式向上移动?

显示软键盘时向上移动布局?