how do you make a container(whose child is a textformfield) expand based on the number of lines of text? (flutter)
Mainly the container wasn't expanding is, because you have inserted
final TextEditingController myController = TextEditingController();
int numLines = 1;
int charLength = 0;
chatBarHeight = 62.5;
//= 52.5;//52.5;
int lastIndexNewLine = 0;
inside the build method of ChatBubbleState; this will cause the chatBarHeight to be 62.5 even if you change it inside onChanged
property of the textFormField.
Also if you wanted the container to expand, First remove the expands
property from the textFormField, this property will expand the textformField to fit it's container not expand while typing and second you don't need the calculation inside the onChanged
property.
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'),
),
),
),
);
}
}
Isis Curiel
Just a geeky software developer who is sometimes funny
Updated on December 25, 2022Comments
-
Isis Curiel over 1 year
I am attempting to make a container expand based on the number of lines in a textformfield as you see in most modern messaging apps. I've searched high and low with no avail and am part of the way there with a possible solution. So i have the container height change based on the number of lines part but the container will not respect the changes. I tried putting a set state after I made the changes but it overrode the textformfield to one line and it reverted the changes. My code can be seen below if you have any suggestions on how to edit my current code or even change my code to make it work as intended I'm open to all suggestions! If you need any more info tag me in a comment or email me [email protected] Referenced 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>';
-
encubos over 3 yearsHave you tried adding to the textField the property: keyboardType: TextInputType.multiline ?
-