Related
I want to align the text "2022" on the bottom of the screen while keeping the image and its neighbor text at the center of the screen.
class SplashScreen extends StatelessWidget {
const SplashScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Globalcolors.mainColor,
body: Container(
padding: const EdgeInsets.all(10),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: Image.asset(
'assets/images/splash_logo.png',
color: Colors.white,
),
),
const Padding(
padding: EdgeInsets.all(50),
child: Text(
'Sample Text',
style: TextStyle(
color: Colors.white,
fontSize: 36,
fontFamily: 'MouseMemoirs'),
),
),
const Text(
'2022',
style: TextStyle(color: Colors.white, fontSize: 12),
),
],
),
),
);
}
}
I tried to use this link to solve the problem. I used Expanded:
const Expanded(
child: Align(
alignment: FractionalOffset.bottomCenter,
child: Text(
'2022',
style: TextStyle(color: Colors.white, fontSize: 12),
),
),
)
But, The result is not good:
You can user Stack and column widgets like
Stack(
children: [
Column(), // contains the image and title
Align(
alignment: Alignment.bottomCenter,
child: Text("2022"),
),
]
)
You can also use Positioned widget to align the text 2022
you can use the bottom method that comes with the scaffold
Scaffold(
bottom : Text("2020")
)
this will make the text always on the bottom of the screen
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'm trying to develop a clone of an App idea from dribble, which can be found here.
Can you please tell me is the code I'm trying to write is correct or not??
As I've tried to wrap a Column with two text Widgets Enclosed in Container ( separate ) and when I'm trying to change the width of one container It changes the margin of the other also.
My Code is :-
class HomeScreen extends StatelessWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
Container(
margin: const EdgeInsets.only(top: 30, left: 20),
child: const Text(
'Find Intrested Events to Join',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 30.0,
wordSpacing: 2,
),
),
width: 200,
),
// -----------------------------------------------------------------
Container(
margin: EdgeInsets.only(left: 20, top: 20),
width: 220,
child: Text(
'We share all events like Charity, workshop, Blood drive, etc.',
style: TextStyle(wordSpacing: 2, height: 1.4),
),
)
],
),
),
);
Can you tell me How to achieve that stage that I can change the Containers' width without affecting the margin of others.
It will be better to use Stack for this case while it contains background image, Also learn more about Stack, Align, Positioned and LayoutBuilder from flutter.dev
Play with this widget ,
class HomeScreen extends StatelessWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(child: LayoutBuilder(
builder: (context, constraints) {
return Stack(
children: [
Container(
color: Colors.amber.withOpacity(.4),
), //background image
Positioned(
left: 20,
top: 30,
child: SizedBox(
width: constraints.maxWidth * .5, // 50% of width
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text(
'Find Intrested Events to Join',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 30.0,
wordSpacing: 2,
),
),
SizedBox(
height: 20,
), //spaces between text
Text(
'We share all events like Charity, workshop, Blood drive, etc.',
style: TextStyle(wordSpacing: 2, height: 1.4),
),
],
),
),
),
Align(
// also Postisioned can be use
alignment: Alignment.bottomCenter,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text("hereh"),
ElevatedButton(onPressed: () {}, child: Text("Button"))
],
),
)
],
);
},
)),
);
}
}
I am using draggableScrollableSheet. I am giving these parameters
DraggableScrollableSheet(initialChildSize: 0.4,maxChildSize: 1,minChildSize: 0.4,builder: (BuildContext context, ScrollController scrollController) {
return SingleChildScrollView(controller: scrollController,
child: Theme(
data: Theme.of(context).copyWith(canvasColor: Colors.transparent),
child: Opacity(
opacity: 1,
child: IntrinsicHeight(
child: Column(mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
SizedBox(height: 10,),
Container(
margin: EdgeInsets.only(right: 300),
decoration: BoxDecoration(
border: Border(
top: BorderSide(
color: Colors.blue,
width: 3,
style: BorderStyle.solid),
),
),
),
Card(
child: Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
Text(
S
.of(context)
.we_have_found_you_a_driver,
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold),
),
SizedBox(
height: 10,
),
Text(S
.of(context)
.driver_is_heading_towards +
' ${widget.order.foodOrders.first.food.restaurant.name}')
],
),
),
],
),
elevation: 5,
),
SizedBox(height: 10,),
Card(
elevation: 5,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
CircleAvatar(
radius: 50.0,
backgroundColor: Colors.white,
child:
Image.asset(
'assets/img/image_not_available.jpg'),
),
Expanded(
child: Column(mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Row(mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Expanded(
child: Text('Test',
textAlign: TextAlign.start,
style: new TextStyle(
color: Colors.black,
fontSize: 16.0,
)),
),
Icon(Icons.star, color: Colors.yellow.shade700,)
],
),
SizedBox(height: 30,),
Row(mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Expanded(
child: Container(
child: Text('Mobile number',
textAlign: TextAlign.start,
style: new TextStyle(
color: Colors.black,
fontSize: 16.0,
)),
),
),
Icon(Icons.phone,),
SizedBox(width: 10,),
Icon(Icons.message),
],
),
],
),
)
]),
),
SizedBox(height: 10,),
Card(
child: Align( alignment: Alignment(-1,1),
child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
Text(
S
.of(context)
.you_ordered_from + ' ${widget.order.foodOrders.first.food.restaurant.name}',
style: TextStyle(
color: Colors.grey,
),
),
SizedBox(
height: 5,
),
Column(children: List.generate(widget.order.foodOrders.length,(index) {
return Text(
'${widget.order.foodOrders[index].food.name}'
);
},),),
Row(
children: <Widget>[
Column(crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('See details', style: TextStyle(fontWeight: FontWeight.bold,color: Colors.blue),),
],
),
],
),
],
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
SizedBox(height: 40,),
Row(
children: <Widget>[
Icon(Icons.monetization_on),
Text(widget.order.foodOrders
.first.price
.toString()),
],
),
],
),
),
],
),
),
elevation: 5,
),
],
),
),
),
),
)
and I also used a single child scroll view and column so that I can show my cards in that column of draggableScrollableSheet. But I want draggableScrollableSheet to take height dynamically instead of defining size. Like now I want to show only 2 to 3 cards and that is taking full screen. But I want it to take the minimum height of the screen. How can we achieve this?
I was struggling with this for a while, and then discovered that the correct way to achieve this is to use ClampingScrollPhysics as the physics parameter of the scroll view.
https://api.flutter.dev/flutter/widgets/ClampingScrollPhysics-class.html
I'm a week into Flutter but I found a solution to this. It might be substandard so correct me if I'm wrong.
So what I've done is create a variable called bsRatio for the bottom sheet. This is will be the height of the child view/widget (or bottom sheet content) divide by the height of the parent/screen. This ratio should be set to the maxChildSize and probably even the initialChildSize of your DraggableScrollableSheet.
So in your parent widget or Widget State class add something like this.
class ParentWidget extends StatefulWidget {
ParentWidget({Key? key}) : super(key: key);
#override
State<ParentWidget> createState() => _ParentWidgetState();
}
class _ParentWidgetState extends State<ParentWidget> {
var bsRatio = 0.4; // Set an initial ratio
#override
Widget build(BuildContext context) {
// The line below is used to get status bar height. Might not be required if you are not using the SafeArea
final statusBarHeight = MediaQuery.of(context).viewPadding.top;
// If you are not using SafeArea Widget you can skip subtracting status bar height from the Window height
final windowHeight = MediaQuery.of(context).size.height - statusBarHeight;
// This below is a callback function that will be passed to the child Widget of the DraggableScrollableSheet ->
childHeightSetter(childHeight) {
// setState rebuilds the UI with the new `bsRatio` value
setState(() {
// The new bottom sheet max height ratio is the height of the Child View/Widget divide by the screen height
bsRatio = childHeight / windowHeight;
});
}
return Scaffold(
backgroundColor: Colors.black12,
body: SafeArea(
child: Stack(
children: [
const SomeBackgroundView(),
DraggableScrollableSheet(
initialChildSize: bsRatio, // here you set the newly calculated ratio as the initial height of the Bottom Sheet
minChildSize: 0.2,
maxChildSize: bsRatio, // here you set the newly calculated ratio as the initial height of the Bottom Sheet
snap: true,
builder: (_, controller) {
return LayoutBuilder(builder: (_, box) {
// Added a container here to add some curved borders and decent looking shadows via the decoration property
return Container(
child: SingleChildScrollView(
controller: controller,
// The child view/widget `MyBottomSheet` below is the actual bottom sheet view/widget
child: MyBottomSheet(childHeightSetter: childHeightSetter),
),
decoration: const BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.grey,
blurRadius: 5.0,
spreadRadius: 2.0
)
],
borderRadius: BorderRadius.all(Radius.circular(20.0))
),
);
});
},
),
],
),
),
);
}
}
And this would be your child view/widget (also your BottomSheet view/widget)
class MyBottomSheet extends StatefulWidget {
// This below is the local callback variable. The `?` is because it may not be set if not required
final ValueSetter<double>? childHeightSetter;
const MyBottomSheet({Key? key, this.childHeightSetter}) : super(key: key);
#override
_MyBottomSheetState createState() => _MyBottomSheetState();
}
class _LoginBottomSheetState extends State<LoginBottomSheet> {
// bsKey is the key used to reference the Child widget we are trying to calculate the height of. Check the `Card` container below
GlobalKey bsKey = GlobalKey();
// this method will me used to get the height of the child content and passed to the callback function so it can be triggered and the ratio can be calculated and set in the parent widget
_getSizes() {
final RenderBox? renderBoxRed =
bsKey.currentContext?.findRenderObject() as RenderBox?;
final cardHeight = renderBoxRed?.size.height;
if (cardHeight != null)
super.widget.childHeightSetter?.call(cardHeight);
}
// This is the function to be called after the Child has been drawn
_afterLayout(_) {
_getSizes();
}
#override
void initState() {
super.initState();
// On initialising state pass the _afterLayout method as a callback to trigger after the child Widget is drawn
WidgetsBinding.instance?.addPostFrameCallback(_afterLayout);
}
#override
Widget build(BuildContext context) {
return Card(
key: bsKey, // This is the key mentioned above used to calculate it's height
color: Colors.white,
shadowColor: Colors.black,
elevation: 40.0,
margin: EdgeInsets.zero,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20.0), topRight: Radius.circular(20.0))),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
// Random children for bottom sheet content
const SizedBox(height: 10.0),
Center(
child: Container(
child: const SizedBox(width: 40.0, height: 5.0),
decoration: BoxDecoration(
color: Colors.grey[400],
borderRadius: BorderRadius.circular(5.0)
),
),
),
const SizedBox(height: 10.0),
const AnotherBottomSheetContentView()
],
),
);
}
}
the initialChildSize is the height of your ScrollView before its actually scrolled, so that means you can actually decide what it would look like.
here is an example![the draggable scrollsheet here has initialChildSize: 0.1,maxChildSize: 1,minChildSize: 0.1,
]1
i'm creating a table in Flutter which contains some TableRows, i just want to add some space between these rows.
Table(
columnWidths: {0: FractionColumnWidth(.4)},
children:[
TableRow(children: [
Text(
'Original Title',
),
Text(
original_title,
),
]),
TableRow(children: [
Text(
'Original Language',
),
Text(
original_language,
),
])
],
);
Here's how i did it.
Create a constant, lets say rowSpacer as
const rowSpacer=TableRow(
children: [
SizedBox(
height: 8,
),
SizedBox(
height: 8,
)
]);
Remember the number of SizedBox widgets to add above should be same as the number of colums in your table. For this case I have 2 colums, hence 2 SizedBoxes.
Now use this constant to give spacing between rows.
Table(
children: [
TableRow(
children: [
Text('Name:'),
Text('Aman kumar')
]),
rowSpacer, //Using the Constant
TableRow(
children: [
Text('Date of Birth:'),
Text('September 27, 1998')
]),
)
Probably not the most efficient way but you can wrap the TableRow in a Padding Class
Padding(
padding: EdgeInsets.all(8.0),
child: const Card(child: Text('Hello World!')),
)
Something along the lines of:
Table(
columnWidths: {0: FractionColumnWidth(.4)},
children:[
TableRow(children: [
Padding(
padding: EdgeInsets.symmetric(vertical: 8.0)
child: Text(
'Original Title',
)),
Padding(
padding: EdgeInsets.symmetric(vertical: 8.0)
child: Text(
original_title,
)),
]),
TableRow(children: [
Padding(
padding: EdgeInsets.symmetric(vertical: 8.0)
child: Text(
'Original Language',
)),
Padding(
padding: EdgeInsets.symmetric(vertical: 8.0)
child: Text(
original_language,
)),
]),
],
);
Padding Class:
https://api.flutter.dev/flutter/widgets/Padding-class.html
EdgeInsets Class:
https://api.flutter.dev/flutter/painting/EdgeInsets-class.html
The easiest thing you can do is to wrap the content of each table cell with a Padding like so:
TableRow (children: [
TableCell(
child:Padding(
padding: const EdgeInsets.all(8.0),
child: Text(EMAIL,
style: TextStyle(
fontWeight: FontWeight.bold,
),),
),
),
TableCell(
child:Padding(
padding: const EdgeInsets.all(8.0),
child: Text(authUser.email),
)
),
])
TableRow(children: [
TableCellPadded(child: const Text('Bla'))
])
class TableCellPadded extends StatelessWidget {
final EdgeInsets? padding;
final Widget child;
final TableCellVerticalAlignment? verticalAlignment;
const TableCellPadded(
{Key? key, required this.child, this.padding, this.verticalAlignment})
: super(key: key);
#override
TableCell build(BuildContext context) => TableCell(
verticalAlignment: verticalAlignment ?? TableCellVerticalAlignment.middle,
child: Padding(padding: padding ?? const EdgeInsets.all(5.0), child: child));
}
Found it here and adjusted it:
https://github.com/flutter/flutter/issues/36816