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:
Related
Does anyone know how to create a grid like this using GridView.builder. Any other alternative will be much appreciated too.
The text in the container should be dynamic as well based on the size of the text.
Thank you
Tried using gridView but the container was always of fixed width and height. The row items was not dynamic as well
You can achieve it by wrapping your list with a Wrap widget. Check the example below:
import 'package:flutter/material.dart';
class NewPage extends StatelessWidget {
const NewPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
List<String> countries = [
'Canada',
'Germany',
'India',
'Taiwan, Province of China',
'United States',
'United Kingdom',
'Kingdom of Saudi Arabia',
'Bangladesh',
'Vietnam',
'Peru',
'Italy'
];
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
const Text('List of countries',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 24)),
const SizedBox(height: 20),
Wrap(
alignment: WrapAlignment.start,
spacing: 10.0,
runSpacing: 10.0,
children: List.generate(
countries.length,
(index) => Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20), color: Colors.grey[400]!),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0),
child: Text(
countries[index],
style: const TextStyle(fontSize: 16),
),
),
)),
)
],
),
),
);
}
}
Please have a look at Wrap. I recommend that you watch the video first provided on link then read the documentation/example.
Is there a way to add a floating action button inside a container? Or at least achieve a similar effect?
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
#override
Widget build(BuildContext context) {
return Container(
child: Padding(
child: Column(
children: <Widget>[
Text('Hello'),
SizedBox(height: 30),
Expanded(
child: Container(
child: TaskList(),
),
)
],
),
),
);
}
}
Ps. I can't use scaffold for a few reasons so don't suggest that.
Yes, you can utilize child property of Container
Container (
child: FloatingActionButton()
)
You can use Container in floatingActionButton: after Flutter 2.0
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
floatingActionButton: GestureDetector(
onTap: (){},
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
margin: const EdgeInsets.symmetric(horizontal:15),
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: AppColors.accentColor2,
borderRadius: BorderRadius.circular(8)
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text('Attendence Summary',style: TextStyle(fontWeight: FontWeight.w300,color: Colors.white,fontSize: 12),),
Text('Present : 20 | Absentees : 10',style: TextStyle(color: Colors.white,fontSize: 14),),
],
),
const Text('Review',style: TextStyle(color: Colors.white),)
],
),
),
],
),
)
I am writing a widget in flutter for a project which should look like this, I am new to flutter and I am trying to imitate the card below
So far this is my code for the widget
import 'package:flutter/material.dart';
import 'package:smooth_star_rating/smooth_star_rating.dart';
class TrailCard extends StatelessWidget {
const TrailCard({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
child: InkWell(
onTap: () {},
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ClipRRect(
borderRadius: BorderRadius.circular(20.0),
child: Image.asset(
'assets/images/cocoa.jpg',
height: 100,
width: 90,
fit: BoxFit.fitHeight,
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Boring Cocoa",
style: TextStyle(
fontSize: 18, fontWeight: FontWeight.bold),
),
Text('Rajhamundry, AP'),
Text(
'Feel the authentic flavours of life while you visit the farms around Rajahmundry',
overflow: TextOverflow.ellipsis,
)
],
),
),
],
)),
)),
);
}
}
I tried using flexible and expanded to try and make the content look the way but I am getting overflow error
You can wrap the Padding widget with a Flexible widget so it takes only the amount of space needed:
NOTE: you should also set the maximum amount of lines the Text widget should take before showing the ellipsis.
Flexible(
// new line
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Boring Cocoa",
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
Text('Rajhamundry, AP'),
Text(
'Feel the authentic flavours of life while you visit the farms around Rajahmundry more text to cause overflow',
// set maximum number of lines the text should take
maxLines: 3, // new line
overflow: TextOverflow.ellipsis,
)
],
),
),
);
RESULT:
Wrap Padding with Expanded
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Boring Cocoa",
style: TextStyle(
fontSize: 18, fontWeight: FontWeight.bold),
),
Text('Rajhamundry, AP'),
Text(
'Feel the authentic flavours of life while you visit the farms around Rajahmundry',
overflow: TextOverflow.ellipsis,
)
],
),
),
)
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,
),
),
),
),
),
],
),
],
),
);
}
}
Is it possible to use PageView to reach the following work?
I'd like to use two containers as the main content for a page in PageView.
I've tried to adjust viewPortFraction but it doesn't work as I expected.
The following effect is used by Apple App store and Prime Video and many apps.
Thanks.
You could try to use an horizontal ListView with PageScrollPhysics() In the physics param.
Instead of using PageView, you could just use a ListView with
scrollDirection: Axis.horizontal
This way you could achieve the same result. You would need to somehow provide an explicit height to your ListView if I am not mistaken.
Below is a working sample.
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Example'),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"Top Games",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18),
),
),
Container(
height: 200,
child: ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
GameCard(
"The Game 1",
"A puzzle game",
"https://lorempixel.com/200/200/abstract/",
),
GameCard(
"The Game 2",
"An even beter game",
"https://lorempixel.com/200/200/sports/2/",
),
GameCard(
"SportMania",
"Editors Choice",
"https://lorempixel.com/200/200/sports/3/",
),
GameCard(
"MonkeySports",
"Monkeys playing Sport",
"https://lorempixel.com/200/200/abstract",
),
],
),
)
],
),
);
}
}
class GameCard extends StatelessWidget {
final String gameTitle;
final String gameDescr;
final String imgUrl;
GameCard(
this.gameTitle,
this.gameDescr,
this.imgUrl,
);
#override
Widget build(BuildContext context) {
return Card(
elevation: 3,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
margin: EdgeInsets.all(5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image.network(
imgUrl,
width: 180,
height: 130,
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
Container(
padding: EdgeInsets.all(4),
width: 180,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
gameTitle,
maxLines: 2,
style: TextStyle(fontWeight: FontWeight.bold),
),
Text(
gameDescr,
maxLines: 2,
),
],
),
),
],
),
);
}
}
Hope this gets you started.
You can using viewportFraction params in PageController;