如何根据文本行数扩展一个容器(其 child 是一个 textformfield)? (扑)

how do you make a container(whose child is a textformfield) expand based on the number of lines of text? (flutter)

我正在尝试根据文本表单字段中的行数扩展容器,正如您在大多数现代消息传递应用程序中看到的那样。我到处搜索都无济于事,但我已经找到了可能的解决方案。所以我根据行数部分更改了容器高度,但容器不会遵守这些更改。在进行更改后,我尝试设置一个设置状态,但它覆盖了文本表单字段到一行并恢复了更改。如果您对如何编辑我当前的代码或什至更改我的代码以使其按预期工作有任何建议,可以在下面看到我的代码我愿意接受所有建议!如果您需要更多信息,请在评论中标记我或给我发电子邮件 isis@hanglyde.com 参考的 https://github.com/flutter/flutter/issues/21943

import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:photosgroup2/recurringwidgets/ombrebackground.dart';
import 'recurringwidgets/size_config.dart';

//import 'package:flutter_chat_bar/flutter_chat_bar.dart';
import 'chat/chatbar.dart';


///MAX BOX SIZE W 291 H 294
///MIN BOX SIZE W 150 H 52
import 'expandedImage.dart';

class ChatDemo extends StatefulWidget {
  //final User user;

  //ChatDemo({this.user});

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

class _ChatDemoState extends State<ChatDemo> with RouteAware {
  double intialHeight = ChatBubbleState.chatBarHeight;
  
  @override

  Widget build(BuildContext context) {
    print('Chat Bar Height $ChatBubbleState.chatBarHeight ');
  if(ChatBubbleState.updated){
    print('Chat Bar Height $ChatBubbleState.chatBarHeight ');
  }  
  
    return Scaffold(
      resizeToAvoidBottomInset: false,
      //resizeToAvoidBottomPadding: true,

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

            Stack(
          children: <Widget>[
            ombreBackground(),
            

            Positioned(
              bottom: MediaQuery.of(context).viewInsets.bottom,
              child: Padding(
                padding: EdgeInsets.only(top: 750 * SizeConfig.heightRatio),
                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(
                                height: 42,
                                width: SizeConfig.screenWidth,
                                decoration: BoxDecoration(
                                  borderRadius: BorderRadius.only(
                                    topLeft: Radius.circular(32.0),
                                    topRight: Radius.circular(32.0),
                                  ),
                                  color:
                                      const Color(0x00000000).withOpacity(0.00),
                                ),
                              ),
                            ),
                          ),
                        ),
                      ),
                    ),
                    Transform.translate(
                      offset: Offset(0, -5 * SizeConfig.heightRatio),
                      child: FlutterChatBar(
                        //addIconSize: 20,
                        avatarRadius: 22,
                        avatarColor: Color(0xffffffff),
                        height: ChatBubbleState.chatBarHeight,//62.5, // OG 60
                        width: SizeConfig.screenWidth, // OG 370
                        color: Color(0x00000000),
                        firstChild: ChatBubble(),
                        secondChild: SecondChild(),
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

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

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

class ChatBubbleState extends State<ChatBubble> {
  static double chatBarHeight;
  static bool updated = true;

  @override
  Widget build(BuildContext context) {
    final TextEditingController myController = TextEditingController();
    int numLines = 1;
    int charLength = 0;
    chatBarHeight = 62.5;
    //= 52.5;//52.5;
    int lastIndexNewLine = 0;

    //print('before $numLines');
    //builds the bar
    return Padding(
      padding: const EdgeInsets.only(bottom: 5),
      child: Container(
        //margin: EdgeInsets.only(top:13,bottom: 5),
        //color: Colors.blue,
        /*constraints: BoxConstraints(
            maxHeight: 176,
          ),*/
        //height: chatBarHeight,
        height: chatBarHeight,
        width: 310.0 * SizeConfig.widthRatio,
        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(
          expands: true,
          textAlign: TextAlign.start,
          style: TextStyle(
              fontSize: 17 * SizeConfig.textMultiplier,
              color: const Color(0xd9343f4b),
              fontFamily: 'Lato'),
          //textAlign: TextAlign.left,
          maxLines: null,
          minLines: null,
          textCapitalization: TextCapitalization.sentences,
          onChanged: (String e) {
            //String partial =e;
            charLength = e.length;
            numLines = '\n'.allMatches(e).length + 1;
            if (e.contains('\n')) {
              lastIndexNewLine = e.indexOf('\n');
              e = e.substring(lastIndexNewLine);
              charLength = e.length - 1;
            }

            if (charLength > 35) {
              numLines++;
            }
            if (numLines == 1) {
              // chatBarHeight = 52.5;
            }
            if (numLines >= 2) {
              print('I have 2 lines.');
              chatBarHeight = 110;

              updated = true;
              print(chatBarHeight);
              print('uPDATED $updated');
            }
            print('after $numLines');
          },
          controller: myController,
          decoration: InputDecoration.collapsed(
              hintStyle: TextStyle(
                color: Color(0x80343f4b),
                fontFamily: 'Lato',
                fontSize: 15 * SizeConfig.textMultiplier,
                //color: const Color(0xd9343f4b),
              ),
              // hintStyle: ,
              hintText: 'Enter Comment'),
        ),
      ),
      // ), //Padding
      //),
    );
  }
}


class SecondChild extends StatelessWidget {
  const SecondChild({
    Key key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    
    return Transform.translate(
      offset:
          Offset(12.5 * SizeConfig.widthRatio, -2.5 * SizeConfig.heightRatio),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.start,
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          
        ],
      ),
    );
  }
}

 
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';




class FlutterChatBar extends StatelessWidget {

  //Height of Chat Bar widget.
  final double height;

  //Width of chat bar widget.
  final double width;

  //Color of chat bar widget.
  final Color color;

  //Initial child which is to be displayed inside chat bar widget.
  //Ex- Message Container which is displayed (Can be TextField also)
  final Widget firstChild;

  //Child which comes after animation (when we tap on add Icon button)
  //Ex - 3 Icons which are displayed
  final Widget secondChild;

  //Color of add Icon by default it is white.
  final Color addIconColor;

  //Color of Circle avatar which has a child of Add Icon , by default color is white30
  final Color avatarColor;

  //Radius of circle avatar , by default it is 30.0
  final double avatarRadius;

  //Size of add Icon , by default it is 30.0
  final double addIconSize;

  FlutterChatBar(
    {
      @required this.height,
      @required this.width,
      @required this.color,
      @required this.firstChild,
      @required this.secondChild,
      this.addIconColor = Colors.white,
      this.avatarColor = Colors.white30,
      this.avatarRadius = 43.0,
      this.addIconSize = 43.0
    }
  );
  @override
  Widget build(BuildContext context) {
    return Container(
      height: height,
      width: width,
      decoration: BoxDecoration(
          //borderRadius: BorderRadius.circular(27.5), 
          color: color),
      child: ContentWidget(
        firstChild: firstChild,
        secondChild: secondChild,
        color: color,
        addIconColor: addIconColor,
        addIconSize: addIconSize,
        avatarRadius: avatarRadius,
        avatarColor: avatarColor,
      ),
    );
  }
}

class ContentWidget extends StatefulWidget {


  final Widget firstChild;
  final Widget secondChild;
  final Color color;
  final Color addIconColor;
  final Color avatarColor;
  final double addIconSize;
  final double avatarRadius;

  ContentWidget(
      {this.firstChild,
      this.secondChild,
      this.color,
      this.addIconColor,
      this.avatarColor,
      this.addIconSize,
      this.avatarRadius});
  @override
  _ContentWidgetState createState() => _ContentWidgetState();
}

class _ContentWidgetState extends State<ContentWidget>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;

  //Animation for firstChild (Ex- Message container)
  Animation<double> _firstChildAnimation;

  //Animation for secondChild (Ex- 3 Icons in a row)
  Animation<double> _secondChildAnimation;

  //Animation for add Icon 
  Animation<double> _iconAnimation;

  @override
  void initState() {
    super.initState();
    _controller =
        AnimationController(duration: Duration(milliseconds: 500), vsync: this)
          ..addListener(() {
            setState(() {});
          });

    _firstChildAnimation = Tween(begin: pi / 4, end: 0.0).animate(CurvedAnimation(
        parent: _controller,
        curve: Curves.easeOut,
        reverseCurve: Curves.easeIn));

    _secondChildAnimation = Tween(begin: 0.0, end: pi / 4).animate(CurvedAnimation(
        parent: _controller,
        curve: Curves.easeIn,
        reverseCurve: Curves.easeOut));

    _iconAnimation = Tween(begin: 0.0, end: pi / 4).animate(CurvedAnimation(
        parent: _controller,
        curve: Curves.easeOut,
        reverseCurve: Curves.easeIn));
  }

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

  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisSize: MainAxisSize.min,
      children: <Widget>[
        /*Padding(
          //padding: const EdgeInsets.all(4.0),
          child:*/ 
          Flexible(
            fit: FlexFit.loose,
            flex: 1,
                      child: GestureDetector(
                onTap: () {
                  if (_controller.status == AnimationStatus.completed) {
                    _controller.reverse();
                  } else {
                    _controller.forward();
                  }
                },
                child: Transform.translate(
                  offset: Offset(20,-3), //15
                                  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: widget.avatarColor,
                    radius: widget.avatarRadius,
                    child: Transform.rotate(
                        angle: _iconAnimation.value,
                        child: SvgPicture.string(
              _svg_nznkw8,
              allowDrawingOutsideViewBox: true,
              fit: BoxFit.fill,
            ),),
                  ),
                                  ),
                ),
              ),
          ),
        //),
        Flexible(
flex:7,
                  child: Stack(
            children: <Widget>[
              Transform.scale(
                scale: _firstChildAnimation.value,
                child: widget.firstChild,
              ),
              Transform.scale(
                scale: _secondChildAnimation.value,
                child: widget.secondChild,
              )
            ],
          ),
        ),
        Flexible
        (
          flex: 1,
          fit: FlexFit.loose,
                  child: Transform.translate(
                    offset: Offset(-20,-3),
                                      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: widget.avatarColor,
                    radius: widget.avatarRadius,
                    child: SvgPicture.string(
                      _svg_52blhh,
                      allowDrawingOutsideViewBox: true,
                      fit: BoxFit.fill,
                    ),),
                                      ),
                ),
        ),
      ],
    );
  }
    }
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-width="1" 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-width="1" stroke-miterlimit="10" stroke-linecap="butt" /></svg>';

主要是容器没有展开,因为你插入了

final TextEditingController myController = TextEditingController();
int numLines = 1;
int charLength = 0;
chatBarHeight = 62.5;
//= 52.5;//52.5;
int lastIndexNewLine = 0;

在 ChatBubbleState 的构建方法中;这将导致 chatBarHeight 为 62.5,即使您在 textFormField 的 onChanged 属性 中更改它也是如此。

此外,如果您希望容器扩展,首先从 textFormField 中删除 expands 属性,此 属性 将扩展 textformField 以适应其容器,而不会在键入时扩展并且其次,您不需要 onChanged 属性.

中的计算
import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
    home: ExpandingText(),
  ));
}

class ExpandingText extends StatefulWidget {
  _ExpandingText createState() => _ExpandingText();
}

class _ExpandingText extends State<ExpandingText> {
  TextEditingController myController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Container(
          width: 310.0,
          decoration: BoxDecoration(
            color: const Color(0xffffffff),
            boxShadow: [
              BoxShadow(
                color: const Color(0x29000000),
                offset: Offset(3, 3),
                blurRadius: 6,
              ),
            ],
          ),
          child: TextFormField(
            textAlign: TextAlign.start,
            style: TextStyle(
                fontSize: 17,
                color: const Color(0xd9343f4b),
                fontFamily: 'Lato'),
            maxLines: null,
            textCapitalization: TextCapitalization.sentences,
            controller: myController,
            decoration: InputDecoration(
                hintStyle: TextStyle(
                  color: Color(0x80343f4b),
                  fontFamily: 'Lato',
                  fontSize: 15,
                ),
                // hintStyle: ,
                hintText: 'Enter Comment'),
          ),
        ),
      ),
    );
  }
}