I was just getting started with flutter and I am trying to create a small profile page I saw on YouTube. I built the page by stacking widgets under the children property of a Column widget. I have put the keyword 'const' before the children list. When I tried to add a Row Widget as one of the children I started to get this error:
The constructor being called isn't a const constructor.
Try removing 'const' from the constructor invocation.
class NetNinjaId extends StatelessWidget {
const NetNinjaId({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'NetNinjaId',
home: Scaffold(
body: Padding(
padding: const EdgeInsets.fromLTRB(0.0, 40.0, 0.0, 0.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
// Email
Padding(
padding: EdgeInsets.fromLTRB(50.0, 50.0, 0.0, 10.0),
child: Row(children: const [
Icon(Icons.mail),
Text(
'abhinav03m#gmail.com',
style: TextStyle(
color: Colors.amber,
fontSize: 20.0,
letterSpacing: 2.0),
),
]),
)
],
),
),
),
);
}
}
Full code here: https://pastebin.com/8aCkHNjN
Error Screen shot:
Things I tried:
Adding const keyword before the list inside the Row widget
Adding const keyword to both widgets inside the children property of Row widget
Removed the beginning const keyword, It worked but it gave more warnings suggesting to use const keyword.
Can anyone explain why this error is happening and what I can do to fix it. Thanks for your help in advance
You need to remove const from
body: Padding(
padding: const EdgeInsets.fromLTRB(0.0, 40.0, 0.0, 0.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [ //here
because Row doesnt use const constructor.
Related
The problem may not be just for the Drawer or DrawerHeader widgets, but on how Expanded or Flexible may work inside a DrawerHeader widget combined with Column and Row widgets.
My code with my Drawer is simply like this:
import 'package:flutter/material.dart';
class PlanningDrawer extends StatefulWidget{
const PlanningDrawer({Key? key}) : super(key: key);
#override
State<PlanningDrawer> createState() => _PlanningDrawerState();
}
class _PlanningDrawerState extends State<PlanningDrawer> {
#override
Widget build(BuildContext context) {
return Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: [
DrawerHeader(
decoration: const BoxDecoration(color: Colors.blue),
child: Padding(
padding: const EdgeInsets.only(bottom: 28),
child: Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(Icons.calendar_month_outlined, size: 48,),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("mPlanning", style: TextStyle(fontSize: 20),),
Text("Application description which may span over many lines")
],
),
)
]
),
Divider(color: Colors.black),
Text("Additional info comes here, which may span over many lines")
],
),
)
)
],
)
);
}
}
And it looks like this when compiling to test on Google Chrome:
As you see I have two overflows.
The upper right one is linked to the long text describing my app, which I want to wrap into multiple lines, it may span many lines. I have tried to wrap it into Flexible, Expanded and some other suggested widgets, but found no luck yet.
The lower I am not sure which it is bound to, since it may be secondary (the long text there wraps nicely though, (not so well seen underneath the warning)).
Could someone please give me a working hint how to get both long texts wrapping ?
Use ListTile Widget instead of Row Widget Please check the below example
class PlanningDrawer extends StatefulWidget {
const PlanningDrawer({Key? key}) : super(key: key);
#override
State<PlanningDrawer> createState() => _PlanningDrawerState();
}
class _PlanningDrawerState extends State<PlanningDrawer> {
#override
Widget build(BuildContext context) {
return Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: [
DrawerHeader(
decoration: const BoxDecoration(color: Colors.blue),
child: Column(
children: const [
ListTile(
title: Text(
"mPlanning",
style: TextStyle(fontSize: 20),
),
subtitle: Text(
"Application description which may span over many
lines"),
leading: Icon(
Icons.calendar_month_outlined,
size: 48,
),
),
Divider(color: Colors.black),
Text(
"Additional info comes here, which may span over many lines ")
],
),
)
],
),
);
}
}
If you need more height, you might replace the DrawerHeader with a Column widget.
class PlanningDrawer extends StatefulWidget {
const PlanningDrawer({Key? key}) : super(key: key);
#override
State<PlanningDrawer> createState() => _PlanningDrawerState();
}
class _PlanningDrawerState extends State<PlanningDrawer> {
#override
Widget build(BuildContext context) {
return Drawer(
child: ListView(
children: [
Expanded(
child: Container(
color: Colors.blue,
padding: EdgeInsets.all(8),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(
Icons.calendar_month_outlined,
size: 48,
),
SizedBox(width: 10),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"mPlanning",
style: TextStyle(fontSize: 20),
),
Text(
"Application description which may span over many linesApplication description which may span over many linesApplication description which may span over many linesApplication description which may span over many linesApplication description which may span over many lines",
softWrap: true,
)
],
),
),
//
],
),
),
Divider(color: Colors.black),
Text(
"Additional info comes here, which may span ov info comes here, which may span ov info comes here, which may span ov info comes here, which may span ov info comes here, which may span ov info comes here, which may span over many lines")
],
),
),
),
],
),
);
}
}
Try using SizedBox to have some space.
The default one with DrawerHeader Also, it provides default padding.
If it is ok to have like this max 2line description with title
You can follow this
class _PlanningDrawerState extends State<PlanningDrawer> {
#override
Widget build(BuildContext context) {
return Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: [
DrawerHeader(
margin: EdgeInsets.zero,
decoration: const BoxDecoration(color: Colors.blue),
child: Column(
children: [
Expanded(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(
Icons.calendar_month_outlined,
size: 48,
),
// sizedBOx if needed
SizedBox(
width: 10,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"mPlanning",
style: TextStyle(fontSize: 20),
),
Expanded(
child: Text(
"Application which may span over many lines",
softWrap: true,
maxLines: 5,
),
)
],
),
)
],
),
),
Divider(color: Colors.black),
Text(
"Additional info comes here, which may span over many lines"),
SizedBox(
height: 28,
)
],
),
),
],
));
}
}
After some more time, and of course both Muhammad Mohsin and Yeasin Sheikh's answers above I came upon a slight change in my code which solved both overflows.
In my fairly simple mind, I thought that DrawerHeader adjusted its height when more widgets where added, but no, you need to expand it manually or make some tweak to do just that.
For the width overflow, I need to wrap the Column which the "mPlanning" and "Application Description..." is placed, in an Expanded widget. Additional you need to put the DrawerHeader inside a SizedBox and constrain its height to some number (200 in this case). Now the DrawerHeader seems to prepare for constraints both in width and height as expected.
import 'package:flutter/material.dart';
class PlanningDrawer extends StatefulWidget{
const PlanningDrawer({Key? key}) : super(key: key);
#override
State<PlanningDrawer> createState() => _PlanningDrawerState();
}
class _PlanningDrawerState extends State<PlanningDrawer> {
#override
Widget build(BuildContext context) {
return Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: [
SizedBox( //<-- Added
height: 200, //<-- Fixed height
child: DrawerHeader(
decoration: const BoxDecoration(color: Colors.blue),
child: Padding(
padding: const EdgeInsets.only(bottom: 28),
child: Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(Icons.calendar_month_outlined, size: 48, color: Colors.white,),
),
Expanded( //<-- Added to let texts in here wrap if necessary.
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("mPlanning", style: TextStyle(fontSize: 20, color: Colors.white)),
Text("Application description which may span over many lines", style: TextStyle(color: Colors.white),)
],
),
),
)
]
),
Divider(color: Colors.white),
Text("Additional info comes here, which may span over many lines", style: TextStyle(color: Colors.white),)
],
),
)
),
)
],
)
);
}
}
And the result is now:
I am making layout for flutter application
What I want to do is
-----------------------
|[i] [text] |
| |
Icon should be the left (padding 5px)
And text should be the center of screen.
At first I should use the Column
However my layout is not the same proportion
It might be simple though , how can I make it??
Stack() is one of the many options that you can use. Something like this:
Stack(
children:<Widget>[
Padding(
padding: EdgeInsets.only(left: 5),
child: Icon(Icons.info),
),
Align(
alignment: Alignment.topCenter,
child: Text("I'm on the top and centered."),
),
],
),
One way you can do this is something like this..
Widget build(BuildContext context) {
return Column(
children: [
Padding(
padding: EdgeInsets.all(5),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Icon(Icons.info),
Text('text'),
Opacity(opacity: 0, child: Icon(Icons.info)),
],
),
),
Padding(
padding: EdgeInsets.all(5),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Icon(Icons.info),
Text('second text'),
Opacity(opacity: 0, child: Icon(Icons.info)),
],
),
),
],
);
}
Result:
I might be late, but I want this answer to be there, if some one would find it better for the development purposes in future time.
We can make a reusable widget, which we can use it inside the main widget. The widget will accept text, and icon to be passed when called
// IconData is the data type for the icons
Widget myWidget(String text, IconData icon) => Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
children: [
// this will be used a left-padding param
SizedBox(width: 20.0),
// using it here
Icon(icon, size: 28.0, color: Colors.greenAccent),
SizedBox(width: 5.0),
// this will take the remaining space, and then center the child
Expanded(child: Center(child: Text(text)))
]
);
To use in the main Widget, just do like this:
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
// calling our widget here
myWidget('FirstText', Icons.alarm),
SizedBox(height: 20.0), // this is used as a top margin
myWidget('SecondText', Icons.notifications)
]
)
If you wanna check out the sources which I used, please see:
Expanded class
SizedBox class
The result you will get is this:
This was an answer I gave a while ago for this same issue, but the other situation was vertical (a Column) instead of horizontal (a Row). Just swap the Row and Columns out for a Column and Rows in this example and you'll get the idea.
My code has grey added in order to show the difference between the two approaches.
A Stack will work, but it's overkill for this, this kind of problem is part of why we have Expandeds and Flexibles. The trick is to use three Flexibles (2 Expandeds and a Spacer). Put the Spacer on top. It and the bottom Expanded must have the same flex value in order to center the middle Expanded.
import 'package:flutter/material.dart';
class CenteringOneItemWithAnotherItemInTheColumn extends StatelessWidget {
const CenteringOneItemWithAnotherItemInTheColumn({
Key key,
}) : super(
key: key,
);
/// Adjust these values as needed
final int sameFlexValueTopAndBottom = 40; // 40%
final int middleFlexValue = 20; // 20%
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Column Alignment Question'),
),
body: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Spacer(),
const Text(
'Cent',
style: TextStyle(
fontSize: 64,
),
),
const Spacer(),
const Text(
'Bot',
style: TextStyle(
fontSize: 64,
),
),
],
),
Column(
children: <Widget>[
/// The key is to have the Spacer and the bottom Expanded
/// use the same value for flex. That will cause the middle
/// child of the Column to be centered vertically.
Expanded(
flex: sameFlexValueTopAndBottom,
child: Container(
width: 100,
color: Colors.grey[300],
),
),
Expanded(
flex: middleFlexValue,
child: const Align(
alignment: Alignment.center,
child: Text(
'Cent',
style: TextStyle(
fontSize: 64,
),
),
),
),
Expanded(
flex: sameFlexValueTopAndBottom,
child: Container(
color: Colors.grey[300],
child: const Align(
alignment: Alignment.bottomCenter,
child: Text(
'Bot',
style: TextStyle(
fontSize: 64,
),
),
),
),
),
],
),
],
),
);
}
}
I'm trying to get a header image to show on a page of an app but it's not showing up and the _header seems to be greyed out in my code. I'm missing something I guess that I'm unsure of. Edit: I need the header to show above the rows of content in the build.
Widget _header() {
return new Container(
child: new Row(
children:<Widget>[
new Column(
children: <Widget>[
Image.asset(
'assets/classes-Image.png',
),
],
),
],
),
);
}
Extra code below:
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: const Text('Learn How to Paint'),
backgroundColor: Color(0xFF202945),
),
body: new Container(
child: ListView(
shrinkWrap: true,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Column(
children: <Widget>[
Row(
children: <Widget>[
new Padding(
padding: const EdgeInsets.only(
left: 20.0,
),
),
Image.asset(
'assets/Profile-Photo.png',
),
new Padding(
padding: const EdgeInsets.only(
right: 20.0,
),
),
Text(
'Katherine G.',
),
],
),
],
),
```
You can achieve this by placing your header widget right before the Row widget.
The header is not showing because you didn't add it in the ListView.
I hope this solves your issue.
You need to be calling _header() from somewhere in your build function and give the result as a child to another widget. It being grayed out probably means you're not calling it.
I'm new to Flutter and I'm attempting to create a Card that has a bottom row and a center Icon or Text. I'm sure this is pretty easy, but I'm struggling . I'm not sure of the best way to do this. Should I create a column with two nested columns?
import 'package:flutter/material.dart';
class Test extends StatelessWidget {
#override
Widget build(BuildContext context) {
return SafeArea(
child: Card(
elevation: 5,
margin: EdgeInsets.fromLTRB(16, 16, 16, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Icon(
Icons.ac_unit,
color: Colors.blue,
),
Row(
children: <Widget>[
Expanded(
child: Container(
height: 50,
color: Colors.blue,
),
)
],
)
],
),
),
);
}
}
Try out this code.
Column(
children: <Widget>[
Expanded(
child: Center(
child: Text('\$250'),
),
),
Text('\$ Total'),
],
)
I'm using Expanded to use entire space of container (Column) which will push text to the bottom. And using Center to put a widget (Text in this code) in the middle of the container.
I have built a chatbot using flutter and DialogueFlow I wanted to add a loading animation before the bot answers the question .
I have already made the loading animation but i am not able to show both, the text and the loading image.
class ChatMessage extends StatelessWidget {
ChatMessage({this.text, this.name, this.type});
final String text;
final String name;
final bool type;
List<Widget> botMessage(context) {
return <Widget>[
Container(
margin: const EdgeInsets.only(right: 16.0),
child: CircleAvatar(child: Image(
image:
NetworkImage('https://cdn3.iconfinder.com/data/icons/customer-support-
7/32/40_robot_bot_customer_help_support_automatic_reply-512.png'),
)
),
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(this.name,
style: TextStyle(fontWeight: FontWeight.bold)),
Container(
margin: const EdgeInsets.only(top: 5.0),
child: Text(text),
),
],
),
),
];
}
List<Widget> loader(context) {
return <Widget>[
Container(
margin: const EdgeInsets.only(right: 16.0),
child: CircleAvatar(child: Image(
image:
NetworkImage('https://cdn3.iconfinder.com/data/icons/customer-support-
7/32/40_robot_bot_customer_help_support_automatic_reply-512.png'),
)
),
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(this.name,
style: TextStyle(fontWeight: FontWeight.bold)),
Container(
margin: const EdgeInsets.only(top: 5.0),
child: Image(
image: AssetImage('assets/loader.gif'),
width: 25,
height: 25,
),
),
],
),
),
];
}
List<Widget> myMessage(context) {
return <Widget>[
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Text(this.name, style: Theme.of(context).textTheme.subhead),
Container(
margin: const EdgeInsets.only(top: 5.0),
child: Text(text),
),
],
),
),
Container(
margin: const EdgeInsets.only(left: 16.0),
child: CircleAvatar(
child: Text(
this.name[0],
style: TextStyle(fontWeight: FontWeight.bold),
)),
),
];
}
#override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.symmetric(vertical: 10.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: this.type ? myMessage(context) : botMessage(context),
),
);
}
}
I have just put loader instead of the botMessage in the last line of the code but how can i just show the loader for 5 seconds or so.
Mainly i want the loading animation like Google Assistant.
There are two ways to do what you want to do.
Create the object with a Boolean flag which is updated to true when data is received and using this flag as condition switch between text & loader widgets.
Use a futurebuilder widget & in future parameter use Future.delay with 5 seconds duration which is returning some value like 1 or true. Then inside the builder of futurebuilder check of snapshot has data. If snapshot don't have data, just show your loader else show your text.
See this video of futurebuilder to understand how it works.
https://youtu.be/ek8ZPdWj4Qo
Edited as #Maadhav asking for code,
Here is a little snippet which might help you.
FutureBuilder(
future: Future.delayed(Duration(seconds: 5), () => true),
builder: (context, snapshot){
if(!snapshot.hasData)
return CircularProgressIndicator();
return Text("Yay");
}
)
Here this FutureBuilder should be the container of your reply bubble in which you can return Text or any other widget according to your need.
For demo click here
The following can be used:
Future.delay(Duration(seconds: 5), () { });