Flutter widgets so confusing [duplicate] - flutter

I’m getting a rendering exception that I don’t understand how to fix. I’m attempting to create a column that has 3 rows.
Row [Image]
Row [TextField ]
Row [Buttons]
Here is my code to build the container:
Container buildEnterAppContainer(BuildContext context) {
var container = new Container(
padding: const EdgeInsets.all(8.0),
child: new Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
buildImageRow(context),
buildAppEntryRow(context),
buildButtonRow(context)
],
),
);
return container;
}
and my buildAppEntryRow code for the text container
Widget buildAppEntryRow(BuildContext context) {
return new Row(
children: <Widget>[
new TextField(
decoration: const InputDecoration(helperText: "Enter App ID"),
style: Theme.of(context).textTheme.body1,
)
],
);
}
When I run I get the following exception:
I/flutter ( 7674): BoxConstraints forces an infinite width.
I/flutter ( 7674): These invalid constraints were provided to RenderStack's layout() function by the following
I/flutter ( 7674): function, which probably computed the invalid constraints in question:
I/flutter ( 7674): RenderConstrainedBox.performLayout (package:flutter/src/rendering/proxy_box.dart:256:13)
I/flutter ( 7674): The offending constraints were:
I/flutter ( 7674): BoxConstraints(w=Infinity, 0.0<=h<=Infinity)
If i change buildAppEntryRow to just a TextField instead like this
Widget buildAppEntryRow2(BuildContext context) {
return new TextField(
decoration: const InputDecoration(helperText: "Enter App ID"),
style: Theme.of(context).textTheme.body1,
);
}
I no longer get the exception. What am I missing with the Row implementation that is causing it to not be able to calculate the size of that row?

(I assume you're using a Row because you want to put other widgets beside the TextField in the future.)
The Row widget wants to determine the intrinsic size of its non-flexible children so it knows how much space that it has left for the flexible ones. However, TextField doesn't have an intrinsic width; it only knows how to size itself to the full width of its parent container. Try wrapping it in a Flexible or Expanded to tell the Row that you're expecting the TextField to take up the remaining space:
new Row(
children: <Widget>[
new Flexible(
child: new TextField(
decoration: const InputDecoration(helperText: "Enter App ID"),
style: Theme.of(context).textTheme.body1,
),
),
],
),

You get this error because TextField expands in horizontal direction and so does the Row, so we need to constrain the width of the TextField, there are many ways of doing it.
Use Expanded
Row(
children: <Widget>[
Expanded(child: TextField()),
OtherWidget(),
],
)
Use Flexible
Row(
children: <Widget>[
Flexible(child: TextField()),
OtherWidget(),
],
)
Wrap it in Container or SizedBox and provide width
Row(
children: <Widget>[
SizedBox(width: 100, child: TextField()),
OtherWidget(),
],
)

you should use Flexible to use a Textfield inside a row.
new Row(
children: <Widget>[
new Text("hi there"),
new Container(
child:new Flexible(
child: new TextField( ),
),//flexible
),//container
],//widget
),//row

The solution is to wrap your Text() inside one of the following widgets:
Either Expanded or Flexible. So, your code using Expanded will be like:
Expanded(
child: TextField(
decoration: InputDecoration(
hintText: "Demo Text",
hintStyle: TextStyle(fontWeight: FontWeight.w300, color: Colors.red)
),
),
),

As #Asif Shiraz mentioned I had same issue and solved this by Wrapping Column in a Flexible, here like this,,
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new Scaffold(
body: Row(
children: <Widget>[
Flexible(
child: Column(
children: <Widget>[
Container(
child: TextField(),
)
//container
],
))
],
mainAxisAlignment: MainAxisAlignment.spaceBetween,
),
));
}
}

The InputDecoration of a TextField can cause an infinite width problem when placed inside a Row. Flutter explains this in the InputDecoration constraints property documentation:
Typically the decorator will fill the horizontal space it is given. ... If null, then the ambient ThemeData.inputDecorationTheme's InputDecorationTheme.constraints will be used. If that is null then the decorator will fill the available width with a default height based on text size.
So, the good news is that the width of a TextField can be constrained without the use of surrounding widgets like Expanded. Simply provide an instance of BoxConstraints to the constraints parameter of the InputDecoration that the TextField widget uses:
const TextField(
decoration: InputDecoration(
constraints: BoxConstraints.tightFor(
width: 200,
),
),
)
As mentioned in the Flutter documentation above, a set of constraints can be applied to several widgets at once by using a Theme with a ThemeData that specifies an InputDecorationTheme with the desired constraints for descendent widgets of the Theme to inherit from and use.

Row(
children: [
Expanded(
flex: 1,
child: Padding(
padding: EdgeInsets.only(left: 5.0,right: 5.0),
child: TextFormField(
controller: commentController,
validator: (String value){
if(value.isEmpty){
// ignore: missing_return
return 'Comment cannot be blank.';
}
},
decoration: InputDecoration(
labelText: "Comment",
labelStyle: TextStyle(
fontFamily: 'Montserrat',
fontWeight: FontWeight.bold,
color: Colors.grey),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.green))),
),
),
),
],
),

I had the same problem.
If you want, you can use Table widget to avoid this kind of issue with TextField

A simple solution is to wrap your Text() inside a Container().
So, your code will be like:
Container(
child: TextField()
)
Here you also get the width and height attribute of a container to adjust the look and feel of your text field. No need to use Flexible if you are wrapping your text field inside of a Container.

If you want your TextField to size itself horizontally based on its content then you can wrap it with IntrinsicWidth widget.
Row(
children: [
Text("From"),
SizedBox(width: 10,),
IntrinsicWidth(child: TextField(
textAlignVertical: TextAlignVertical.center,
decoration: InputDecoration(
hintText: "Start Date Start Date Start Date",
hintStyle: TextStyle(color: Colour.pBlue, fontSize: 14),
border: InputBorder.none,
),
),),
SizedBox(width: 10,),
Text("To"),
SizedBox(width: 10,),
IntrinsicWidth(child: IntrinsicWidth(child: TextField(
textAlignVertical: TextAlignVertical.center,
decoration: InputDecoration(
hintText: "End Date",
hintStyle: TextStyle(color: Colour.pBlue, fontSize: 14),
border: InputBorder.none,
),
),)),
],
)
But before using it in your code make sure to know what Flutter says about this widget.
Creates a widget that sizes its child to the child's intrinsic width.
This class is relatively expensive. Avoid using it where possible.

the best solution is with absouluts space values
Row(
children: <Widget>[
SizedBox(
width: MediaQuery.of(context).size.width * 0.3,
child: _telephonePrefixInput()
),
SizedBox(width: MediaQuery.of(context).size.width * 0.02),
Expanded(child: _telephoneInput()),
],
),

Related

Flutter text yellow underline

Can anybody know what's wrong with my code cause i m getting a yellow underline text. enter image description here
Here is my code:
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: EdgeInsetsDirectional.fromSTEB(10, 100, 10, 460),
child: RichText(
text: TextSpan(
style: DefaultTextStyle.of(context).style,
children: [
TextSpan(
text: "asdad",
style:
TextStyle(color: Colors.black.withOpacity(0.6)))
]),
)),
const TextField(
decoration: InputDecoration(
hintText: 'What s your name?', border: OutlineInputBorder()),
),
],
),
),
);
}
I've tried to wrap with MaterialApp, not working
You need to have a MaterialApp and you should not have everything in only one widget like this.
DefaultTextStyle.of(context).style is not able to reach the MaterialApp to get the default text style. It has to be in another widget class (or a Builder widget) so that the context lets you reach the MaterialApp.

Show the suffixIcon after the suffixText in a textField

I just wanted to show the suffixIcon after the suffixText.
Now I know that in the InputDecoration documentation says explicitly that it will show the suffixText before the suffixIcon.
What would I like to do is:
the '*' represents that it's a mandatory field.
And I'm getting this :
is there a way for me to change the order of the suffixes in my TextField?
I tried using SizedBox, or Container widgets but never got the result I wanted.
You can use suffix (edit: suffixIcon) property and pass in a Row widget instead. Put both elements in the Row, and you can decide exactly how you want them to appear. For example:
Soure code:
TextField(
decoration: InputDecoration(
suffixIcon: Row(
mainAxisSize: MainAxisSize.min, // <-- important
children: const [
Icon(Icons.visibility, color: Colors.grey),
SizedBox(width: 4), // add a small gap
Text('*'), // second element
],
),
),
)
Try below code, use Row() widget for suffixIcon
TextField(
decoration: InputDecoration(
suffix: Row(
mainAxisSize: MainAxisSize.min,
children: const [
Icon(
Icons.visibility,
color: Colors.green,
),
SizedBox(width: 5),
Text(
'*',
style: TextStyle(
color: Colors.red,
),
),
],
),
),
),
Your result screen->
You can modify your suffixIcon property to:
suffixIcon: Center(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Icon(Icons.remove_red_eye),
Text(
"*",
style: TextStyle(color: Colors.red),
)
],
),
),
The alignments here are important to maintain.

How to give all Row children the same height

I am having a hard time making a Row's two children, i.e. a TextField and a RaisedButton the same height. The button is always shorter in height. I can do that with SizedBox, but it is a fixed height and is manual. Here's what my code and UI looks like now:
Row(
children: [
Padding(
padding: _padding,
child: SizedBox(
width: 200,
child: TextField(
keyboardType: TextInputType.number,
decoration: InputDecoration(
labelText: 'Answer',
border: OutlineInputBorder(borderRadius: BorderRadius.circular(4.0))
),
),
),
),
RaisedButton(
onPressed: _evaluate,
child: Text('Evaluate'),
),
],
),
I wonder if there is a recommended way how to make a Row's children the same height.
By the way, the black lines on the sides are for the emulator frames.
It's not good to wrap textfield with container and give it height, some cases textfield crack when typing, you can use inside of you Textfield -> InputDecoration;
contentPadding: EdgeInsets.all(20),
you can adjust textfield height from here.
Try to wrap Row with SizedBox or container with fixed height
You can wrap the Row widget with a SizedBox widget and give it a desired height:
I added a demo using your code as an example:
SizedBox( // new line
height: 60, // give it a desired height here
child: Row(
children: [
Padding(
padding: _padding,
child: SizedBox(
width: 200,
child: TextField(
keyboardType: TextInputType.number,
decoration: InputDecoration(
labelText: 'Answer',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(4.0))),
),
),
),
RaisedButton(
onPressed: _evaluate,
child: Text('Evaluate'),
),
],
),
),

Placing the cursor at the top left of a vertically stretched TextField?

I'm trying to make a page through which the user can create a note for my Notes app. This is my build method so far:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Add Note"),
actions: <Widget>[
FlatButton(
child: Icon(
Icons.save,
color: Colors.white,
),
)
],
),
body: Center(
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
TextField (
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: "Title",
),
textCapitalization: TextCapitalization.words,
),
SizedBox(
height: 16,
),
Expanded(
child: Container(
child: TextField (
expands: true,
maxLines: 25,
decoration: InputDecoration(
border: OutlineInputBorder(),
),
),
),
)
],
),
),
)
);
}
This is how the page looks right now. How do I ensure that the cursor of the second TextField is placed at the top left and make said TextField stretch to fit the remaining height?
You should set the textAlign property of the TextField to start
textAlign: start
Edit:
based on #Andy_519's and community input please use the following
textAlignVertical: top

Flutter Layout: How can I put a Row inside a Flex (or another Row) in Flutter? Also using Stack widget

I need to put 2 composed widgets in one Row:
The composed widget is named "boxText". I need it twice, each inside a Border with two Texts and a TextFormField like:
Stack
Image and others
Form
Row or Flex or Whatever:
+------------------------------+ +------------------------------+
| Text Text TextFormField | | Text Text TextFormField |
+------------------------------+ +------------------------------+
My code (and tears):
IMPORTANT: Exception occurs only when TextFormField is added.
#override
Widget build(BuildContext context) {
// Composed Widget
Widget boxText = new Container(
decoration: new BoxDecoration(
border: new Border.all(
color: Colors.cyan[100],
width: 3.0,
style: BorderStyle.solid,
),
),
margin: new EdgeInsets.all(5.0),
padding: new EdgeInsets.all(8.0),
child: new Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Text(
'Text',
style: null,
),
new Text(
'Text',
style: null,
),
new TextFormField(
decoration: const InputDecoration(
hintText: '',
labelText: 'label',
),
obscureText: true,
),
],
),
);
return new Scaffold(
key: _scaffoldKey,
body: new Stack(
alignment: AlignmentDirectional.topStart,
textDirection: TextDirection.ltr,
fit: StackFit.loose,
overflow: Overflow.clip,
children: <Widget>[
new Container(
color: Colors.red[200],
margin: new EdgeInsets.only(
left: MediaQuery.of(context).size.width * 0.05,
right: MediaQuery.of(context).size.width * 0.05,
top: MediaQuery.of(context).size.height * 0.4,
bottom: MediaQuery.of(context).size.height * 0.1,
),
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: new Form(
key: _formKey,
child: new ListView(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
children: <Widget>[
new Flex(
direction: Axis.horizontal,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
boxText,
boxText,
],
),
],
),
),
),
],
),
);
}
How, if possible, can put this widgets to work without:
══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞══
The following assertion was thrown during performLayout():
An InputDecorator, which is typically created by a TextField, cannot
have an unbounded width.
This happens when the parent widget does not provide a finite width
constraint. For example, if the InputDecorator is contained by a Row,
then its width must be constrained. An Expanded widget or a SizedBox
can be used to constrain the width of the InputDecorator or the
TextField that contains it.
'package:flutter/src/material/input_decorator.dart':
Failed assertion: line 945 pos 7: 'layoutConstraints.maxWidth <
double.infinity'
Wrap BOTH your Container and TextFormField inside a Flexible widget.
Widget boxText = new Flexible(child: new Container(
decoration: new BoxDecoration(
border: new Border.all(
color: Colors.cyan[100],
width: 3.0,
style: BorderStyle.solid,
),
),
margin: new EdgeInsets.all(5.0),
padding: new EdgeInsets.all(8.0),
child: new Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Text(
'Text',
style: null,
),
new Text(
'Text',
style: null,
),
new Flexible (child: new TextFormField(
decoration: const InputDecoration(
hintText: '',
labelText: 'label',
),
obscureText: true,
),),
],
),
));
The problem is that your Container is relying on its parent to decide its width. Since it has no parent, it is infinitely wide.
To fix the problem, give it a parent who tells its child how to handle width. A Flexible or Expanded does that. Expanded tells its child to be as big as possible (to expand) and a Flexible tells its child to be as small as possible (to shrink).
It sounds to me like an Expanded would be your best bet:
Change your code:
// Composed Widget
Widget boxText = new Container(
decoration: new BoxDecoration(
// all your other code here
);
to
// Composed Widget
Widget boxText = Expanded( // <-- Add this Expanded widget
child: new Container(
decoration: new BoxDecoration(
// all your other code here
),
);
child: Row(
children: <Widget>[
Expanded(
child: TextField(
decoration: InputDecoration(hintText: "text"),
),
),
Text("unit"),
],
)),