Related
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()),
],
),
return Scaffold(
body: Container(
height: MediaQuery.of(context).size.height,
child: Column(
children: [
Padding(
padding: const EdgeInsets.only(top: 50),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Padding(
padding: EdgeInsets.only(top: 2),
child: FaIcon(
FontAwesomeIcons.compass,
color: orange,
size: 26,
),
),
],
),
),
SizedBox(
height: 25,
),
Text(
'The final step for exploration.',
style: homepageSubtitle,
),
SizedBox(
height: 50,
),
TextFormWidget(
onChanged: () => null,
controller: _usernameController,
labelText: 'Username',
hintText: 'example#gmail.com'),
TextFormWidget(
onChanged: () => (value) => _checkPassword(value),
controller: _passwordController,
labelText: 'Password',
hintText: 'Min. 8 characters'),
Here, I created the page you see in the image.
return Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 20,
),
child: TextFormField(
onChanged: onChanged(),
keyboardType: TextInputType.text,
controller: controller,
decoration: InputDecoration(
contentPadding:
const EdgeInsets.symmetric(horizontal: 20, vertical: 20),
labelText: labelText,
hintText: hintText,
labelStyle: labelTextStyle,
hintStyle: hintTextStyle,
),
),
),
],
);
Here is the TextFormWidget I created.
If I click on a TextFormField to enter a value, I get an overflowed error. What should I wrap the widget I created or the place where I show this widget so that I don't get this error?
Because keyboard appear make your Column doesn't has enough space. Try wrap your Column with SingleChildScrollView:
SingleChildScrollView(
child : Column(
children: [
// your children
]
);
)
Set this in your Scaffold:
resizeToAvoidBottomInset: false,
When the keyboard opens you have less space on the screen, and now your Column doesn't fit in the space you have.
Simple solution is to wrap it with SingleChildScrollView which will make it scrollable and therefore remove overflow.
I've used sample code for the answer.
class DemoApp extends StatelessWidget {
const DemoApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Column(
children: [
Container(
height: 600,
color: Colors.deepPurple,
),
TextFormField(
decoration: const InputDecoration(labelText: 'Username'),
),
TextFormField(
decoration: const InputDecoration(labelText: 'Password'),
)
],
),
),
);
}
}
Output:
Bottom Overflow Error:
There are 3 ways to solve this issue:
1. Adding resizeToAvoidBottomInset: false in Scaffold
If text fields are close to the bottom of the screen, this approach is not recommended because the keyboard can hide the text fields.
Scaffold(
resizeToAvoidBottomInset: false,
body: Column( ...
Output:
2. Wrap the Column widget within SingleChildScrollView
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SingleChildScrollView(
child: Column( ...
Output:
3. By changing the Column widget to the ListView widget
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: ListView(
children: [ ...
Output:
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
What I want to achieve is to have a text widget inside a Column of fixed height. When the text is long I want the overflow property which is set to TextOverflow.ellipsis to kick in. The Text widget has its maxLines property set to a high value to allow it to wrap down. But there are other widgets in the column too, both before and after the text widget. The text widget is in an Expanded widget so that it takes up as much room in the column. Full code is pasted below.
The problem with this setup is that the text is overflowing its container parent. I have a border decoration on the container that shows this happening. Why is this happening and how do I fix it.
import 'package:flutter/material.dart';
void main() {
runApp(App());
}
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Overflow"),
),
body: Center(
child: Container(
width: 200.0,
height: 250.0,
child: Card(
child: Column(children: <Widget>[
Image.asset(
"assets/bereket.jpg",
width: double.infinity,
fit: BoxFit.cover,
),
Expanded(
child: Container(
padding: EdgeInsets.all(8.0),
child: (Column(
children: [
Text(
"በረከት ስምኦን፡ «ወይዘሮ አና ጎሜዝ፤ እርስዎ አያገባዎትም! አርፈው ይቀመጡ በልልኝ»",
maxLines: 2,
style: Theme.of(context)
.primaryTextTheme
.subhead
.copyWith(
color: Colors.black,
),
overflow: TextOverflow.ellipsis),
Expanded(
child: Container(
decoration: BoxDecoration(
border: Border.all(
color: Colors.green, width: 2.0),
),
child: Text(
"""ባለፉት ሁለት አስርት ዓመታት በኢትዮጵያ ፖለቲካ ከፍተኛ ተጽእኖ ፈጣሪ የነበሩት አቶ በረከት ስምኦን በቅርቡ ከብአዴን ማእከላዊ ኮሚቴ አባልነት መታገዳቸው ይታወሳል።
አቶ በርከት የብአዴን ውሳኔን በተመለከተ እና የወደፊት የፖለቲካ ህይወታቸው ምን ሊሆን እንደሚችል ለቢቢሲ አጋርተዋል።""",
maxLines: 10,
style: Theme.of(context)
.primaryTextTheme
.caption
.copyWith(color: Colors.black),
overflow: TextOverflow.ellipsis,
))),
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
width: 20.0,
height: 20.0,
child: Image.asset("assets/bbc.png"),
),
SizedBox(width: 8.0),
Text('ቢቢሲ - ከሁለት ሰአት በፊት',
style: Theme.of(context)
.textTheme
.caption
.copyWith(fontSize: 10.0))
],
)
],
))))
]))),
),
),
);
}
}
Try wrapping your column with 'Flexible' instead of expandable.
I had the same issue with text overflowing in column and wrapping column itself with 'flexible' allowed to make text smaller.
Flexible(
child: Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Text(
'Name',
style: CustomTextStyle.blueTitle14(context),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 4.0),
child: Text('Long text'),
),
],
),
),
),
Based on my experiences, you should assign a fixed width to the Container containing the overflowing text, as per this post. Flutter- wrapping text .
In present version of flutter (presently 3.0) you dont have to use Flexible or Expanded as Column's child automatically expandes to fill the content of child .
For ellipses define the maxLine attribute.
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text(
"This is very very very very very very very very very very very very very very very very very long text in Row 1 of Column",
maxLines: 2,
style: TextStyle(
backgroundColor: Colors.green, overflow: TextOverflow.ellipsis),
),
Text("This is very very long text in Row 2 of Column",
style: TextStyle(
overflow: TextOverflow.ellipsis,
backgroundColor: Colors.yellow))
],
)
In the code below, textAlign property doesn't work. If you remove DefaultTextStyle wrapper which is several levels above, textAlign starts to work.
Why and how to ensure it is always working?
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
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 DefaultTextStyle(style: new TextStyle(fontSize: 10.0), child: new Column(children: <Widget>[
new Text("Should be left", textAlign: TextAlign.left,),
new Text("Should be right", textAlign: TextAlign.right,)
],))
);
}
}
Both approaches, suggested by Remi apparently don't work "in the wild". Here is an example I nested both inside rows and columns. First approach doesn't do align and second approach makes application just crash:
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return new Directionality(textDirection: TextDirection.ltr, child: new DefaultTextStyle(
style: new TextStyle(fontSize: 10.0, color: Colors.white),
child: new Column(children: <Widget>[
new Row(children: <Widget>[
new Container(color: Colors.grey, child: new Column(children: <Widget>[
new Align(alignment: Alignment.centerLeft, child: new Text("left")),
new Align(alignment: Alignment.centerRight, child: new Text("right")),
],)),
new Container(color: Colors.grey, child: new Column(children: <Widget>[
new Align(alignment: Alignment.centerLeft, child: new Text("left")),
new Align(alignment: Alignment.centerRight, child: new Text("right")),
],)),
],),
/*new Row(children: <Widget>[
new Container(color: Colors.grey, child: new Column(children: <Widget>[
new SizedBox(width: double.infinity, child: new Text("left", textAlign: TextAlign.left,)),
new SizedBox(width: double.infinity, child: new Text("right", textAlign: TextAlign.right)),
],)),
new Container(color: Colors.grey, child: new Column(children: <Widget>[
new SizedBox(width: double.infinity, child: new Text("left", textAlign: TextAlign.left)),
new SizedBox(width: double.infinity, child: new Text("right", textAlign: TextAlign.right)),
],)),
],)*/]
)));
}
}
What I get from code is
i.e. text is centered, ignoring alignment of Align element.
DefaultTextStyle is unrelated to the problem. Removing it simply uses the default style, which is far bigger than the one you used so it hides the problem.
textAlign aligns the text in the space occupied by Text when that occupied space is bigger than the actual content.
The thing is, inside a Column, your Text takes the bare minimum space. It is then the Column that aligns its children using crossAxisAlignment which defaults to center.
An easy way to catch such behavior is by wrapping your texts like this :
Container(
color: Colors.red,
child: Text(...)
)
Which using the code you provided, render the following :
The problem suddenly becomes obvious: Text don't take the whole Column width.
You now have a few solutions.
You can wrap your Text into an Align to mimic textAlign behavior
Column(
children: <Widget>[
Align(
alignment: Alignment.centerLeft,
child: Container(
color: Colors.red,
child: Text(
"Should be left",
),
),
),
],
)
Which will render the following :
or you can force your Text to fill the Column width.
Either by specifying crossAxisAlignment: CrossAxisAlignment.stretch on Column, or by using SizedBox with an infinite width.
Column(
children: <Widget>[
SizedBox(
width: double.infinity,
child: Container(
color: Colors.red,
child: Text(
"Should be left",
textAlign: TextAlign.left,
),
),
),
],
),
which renders the following:
In that example, it is TextAlign that placed the text to the left.
Specify crossAxisAlignment: CrossAxisAlignment.start in your column
In Colum widget Text alignment will be centred automatically, so use crossAxisAlignment: CrossAxisAlignment.start to align start.
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(""),
Text(""),
]);
textAlign property only works when there is a more space left for the Text's content. Below are 2 examples which shows when textAlign has impact and when not.
No impact
For instance, in this example, it won't have any impact because there is no extra space for the content of the Text.
Text(
"Hello",
textAlign: TextAlign.end, // no impact
),
Has impact
If you wrap it in a Container and provide extra width such that it has more extra space.
Container(
width: 200,
color: Colors.orange,
child: Text(
"Hello",
textAlign: TextAlign.end, // has impact
),
)
Set alignment: Alignment.centerRight in Container:
Container(
alignment: Alignment.centerRight,
child:Text(
"Hello",
),
)
You can use the container, It will help you to set the alignment.
Widget _buildListWidget({Map reminder}) {
return Container(
color: Colors.amber,
alignment: Alignment.centerLeft,
padding: EdgeInsets.all(20),
height: 80,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
alignment: Alignment.centerLeft,
child: Text(
reminder['title'],
textAlign: TextAlign.left,
style: TextStyle(
fontSize: 16,
color: Colors.black,
backgroundColor: Colors.blue,
fontWeight: FontWeight.normal,
),
),
),
Container(
alignment: Alignment.centerRight,
child: Text(
reminder['Date'],
textAlign: TextAlign.right,
style: TextStyle(
fontSize: 12,
color: Colors.grey,
backgroundColor: Colors.blue,
fontWeight: FontWeight.normal,
),
),
),
],
),
);
}
For maximum flexibility, I usually prefer working with SizedBox like this:
Row(
children: <Widget>[
SizedBox(
width: 235,
child: Text('Hey, ')),
SizedBox(
width: 110,
child: Text('how are'),
SizedBox(
width: 10,
child: Text('you?'))
],
)
I've experienced problems with text alignment when using alignment in the past, whereas sizedbox always does the work.
You can align text anywhere in the scaffold or container except center:-
Its works for me anywhere in my application:-
new Text(
"Nextperience",
//i have setted in center.
textAlign: TextAlign.center,
//when i want it left.
//textAlign: TextAlign.left,
//when i want it right.
//textAlign: TextAlign.right,
style: TextStyle(
fontSize: 16,
color: Colors.blue[900],
fontWeight: FontWeight.w500),
),
Text(' Use textAlign: TextAlign.center',
style: TextStyle(fontWeight: FontWeight.w900,fontSize: 20,),
textAlign: TextAlign.center,)
Always use textAlign When trying to direct you text