I'm building a layout with a GridView and Cards. I want to put a color to the bottom of each card. I found this question Fill an area with color in Flutter and tried to do the same trick for bottom, but each time The SizedBox Overflows the round card corners. Any idea of how to fix this?
The sample code below shows the issue. I try to color the bottom part of the card, and when I do this, the corners of the card are lost, like overflow from the Container.
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.lightBlue,
appBar: AppBar(
title: Text(widget.title),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Card(
margin: EdgeInsets.all(20),
elevation: 10,
child: SizedBox(
height: 100,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text("line1"),
Text(
"line2",
),
Expanded(
child: Container(
/*color: Colors.orange,*/ child: Text("Bottom"),
)),
],
),
),
),
Expanded(
child: Container(),
)
],
),
);
}
Try using BoxDecoration in your Container and use the same radius as your Card (4.0)
Expanded(
child: Container(
decoration: BoxDecoration(
color: Colors.orange,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(4.0),
bottomRight: Radius.circular(4.0))),
child: Text("Bottom"),
),
),
Related
I imported [sliding up panel][2] from pub.dev and everything is good except for one issue. I'm looking for a way to center the 'blue circle' vertically. (in between 'red appbar' and 'buttom slider') I tried wraping the code with 'center' or using mainaxisalignment but it doesn't work. Other things I tried which I found on google just gave me an errors. Please help.
Thanks in advance
return Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(200),
child: AppBar(
backgroundColor: Colors.pinkAccent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(bottom: Radius.circular(100))
),
flexibleSpace: Container(
alignment: Alignment.center,
child: Text(
'Red AppBar',
style: TextStyle(
color: Colors.white,
fontSize: 50.0,
fontWeight: FontWeight.bold
),
),
),
),
),
body: SlidingUpPanel(
renderPanelSheet: false,
panel: _floatingPanel(),
collapsed: _floatingCollapsed(),
body: ElevatedButton(
onPressed: () {},
child: Text('Blue Circle'),
style: ElevatedButton.styleFrom(
shape: CircleBorder(),
padding: EdgeInsets.all(20),
),
)
),
);
Widget _floatingCollapsed() {
return Container(
decoration: BoxDecoration(
color: Colors.blueGrey,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(24.0), topRight: Radius.circular(24.0)),
),
margin: const EdgeInsets.fromLTRB(24.0, 24.0, 24.0, 0.0),
child: Center(
child: Text(
"buttom slider",
style: TextStyle(color: Colors.white),
),
),
);
}
Widget _floatingPanel() {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(24.0)),
boxShadow: [
BoxShadow(
blurRadius: 20.0,
color: Colors.grey,
),
]
),
margin: const EdgeInsets.all(24.0),
child: Center(
child: Text("LEVEL INFO"),
),
);
}
Also, what could be the best way to give margin to the 'blue circle' so it won't touch the far left and far right side of the screen?
The SlidingUpPanel's body is using Stack, also getting full screen size. You can check
#override
Widget build(BuildContext context) {
return Stack(
alignment: widget.slideDirection == SlideDirection.UP
? Alignment.bottomCenter
: Alignment.topCenter,
children: <Widget>[
//make the back widget take up the entire back side
widget.body != null
? AnimatedBuilder(
animation: _ac,
builder: (context, child) {
return Positioned(
top: widget.parallaxEnabled ? _getParallax() : 0.0,
child: child ?? SizedBox(),
);
},
child: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: widget.body,
),
)
You can play with Align on body and wrapping with SizedBox. You can use LayoutBuilder or MediaQuery to provide size.
body: SlidingUpPanel(
renderPanelSheet: false,
panel: _floatingPanel(),
collapsed: _floatingCollapsed(),
body: Align(
alignment: Alignment(0.0, -.3), //play with it
child: SizedBox(
width: 200,
height: 200,
child: ElevatedButton(
As per the documentation of sliding_up_panel, the body represents the widget that lies underneath the sliding panel and it automatically sizes itself to fill the screen. So it occupies full screen. Since you expanded AppBar to 200 unit, the body Widget was pushed down, hence you are seeing the centre point also pushed down by 200 unit. If you change the body height to occupy full screen from the start, by setting the Scaffold property extendBodyBehindAppBar with true, you will place the widget in the correct centre point.
if you add the below line immediately after the Scaffold. You will get desired result.
return Scaffold(
extendBodyBehindAppBar:true,
my idea is to create a card widget that has an image on the left and corresponding text data on the right side. The picture should always take the full height and 1/3 of the width (I used expanded with flex to get this. Not sure if this is the best way). The image should be placed in a stack in order to stack further widgets.
My problem is that I am not able to place the image in the stack without specifying a fixed height. I tried Positoned.fill but this did not work for me.
This is my code so far for the card:
Widget build(BuildContext context) {
return Card(
elevation: 5,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
child: Row(
children: [
Expanded(
child: Stack(
children: [
Container(
// child: Positioned.fill(
// child: ClipRRect(
// borderRadius: BorderRadius.circular(15.0),
// child: Image(
// image: AssetImage("assets/eyes.jpg"),
// fit: BoxFit.cover,
// ),
// ),
// ),
),
],
),
),
Expanded(
flex: 2,
child: Container(
color: Colors.grey,
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 15.0, vertical: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("This is a test"),
SizedBox(height: 10),
Text("This is a test test"),
SizedBox(height: 10),
Text("This is a test test test"),
SizedBox(height: 10),
Text("This is a test test"),
SizedBox(height: 10),
Text("This is a test"),
],
),
),
),
),
],
),
);
}
Here is a picture of the current state. The image should take up the entire white area on the left side of the card.
Instead of adding a child image widget inside your container, you can add a decoration image to the container itself. Here's how you do it:
Container(
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: AssetImage("url"),
),
),
),
I want the Container attached to the body of the Scaffold to occupy the space of it's child, which is the Padding widget in this case.
return Scaffold(
backgroundColor: Colors.lightBlue,
appBar: AppBar(
// backgroundColor: AppColors.grey,
elevation: 0.0,
backgroundColor: Colors.transparent,
leading: IconButton(
icon: Icon(
Icons.arrow_back,
color: Colors.black,
),
onPressed: () => Navigator.pushReplacementNamed(context, '/'),
),
),
body: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30.0),
topRight: Radius.circular(30.0),
),
boxShadow: kBoxShadow,
),
child: Padding(
padding: EdgeInsets.all(kSpacingUnit * 3.0),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
EmailSignInForm(),
SizedBox(height: kSpacingUnit * 4.0),
SocialMediaLoginWidget(),
],
),
),
),
);
Below is the screenshot for the above code:
But I also want the padding widget to be pushed to the bottom of the screen. To achieve this I wrapped the Padding widget with the Expanded widget, and later wrapped the Expanded widget with a Column widget, as shown below:
return Scaffold(
backgroundColor: Colors.lightBlue,
appBar: AppBar(
// backgroundColor: AppColors.grey,
elevation: 0.0,
backgroundColor: Colors.transparent,
leading: IconButton(
icon: Icon(
Icons.arrow_back,
color: Colors.black,
),
onPressed: () => Navigator.pushReplacementNamed(context, '/'),
),
),
body: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30.0),
topRight: Radius.circular(30.0),
),
boxShadow: kBoxShadow,
),
child: Column(
children: [
Expanded(
child: Padding(
padding: EdgeInsets.all(kSpacingUnit * 3.0),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
EmailSignInForm(),
SizedBox(height: kSpacingUnit * 4.0),
SocialMediaLoginWidget(),
],
),
),
),
],
),
),
);
Now that the contents of the Padding widget have got pushed to the bottom of the screen, but the Expanded widget, tries to occupy all the available space. I don't want this to happen.
I don't want the height of the Padding widget to increase. Below is the screenshot after updating the code:
Another issue that's concerning me is, where should I be adding the SingleChildScrollView, as I would experience the "Bottom overflowed by -- px" error when the user would tap on the TextFormFields to input the email and password.
I did raise this issue earlier as well but wasn't much luck, so thought would organize the code and explain it in detail so that it would be easy for others to understand and help.
Thank you so much for your help in advance.
AFTER APPLYING SOLUTION SUGGESTED BY #SoundConception
try adding this to your Column widget :
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
In your first code example you have:
...
body: Container(
...
child: Padding(
padding: EdgeInsets.all(kSpacingUnit * 3.0),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
...
],
),
),
),
The mainAxisSize: MainAxisSize.min specifies that the Column should be as small as possible in height, effectively shrink wrapping it to the height of its children.
The Padding just adds the specified dp of padding around Column widget.
This means the child of the Container has a fixed height equal to the sum of the Column children heights plus (kSpacingUnit * 3.0) dp of padding top and bottom.
Since the Container child height is fixed, the Container will size itself to the height of it's child.
In your second code example you have:
body: Container(
...
child: Column(
children: [
Expanded(
child: Padding(
padding: EdgeInsets.all(kSpacingUnit * 3.0),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
...
],
),
),
),
],
),
),
Here the outermost Column has a single child that is an Expanded which means this will take up all the available room in the Column.
The innermost Column has mainAxisAlignment: MainAxisAlignment.end meaning its children will align to the bottom of the Column. The height of your Padding has not expanded.
You ask about using a SingleChildScrollView. I assume you want the white background decoration to remain stationary, and only the contents of the Column should be able to scroll.
Try something like the following:
return Scaffold(
...
body: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30.0),
topRight: Radius.circular(30.0),
),
boxShadow: kBoxShadow,
),
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(kSpacingUnit * 3.0),
child: Column(
children: <Widget>[
EmailSignInForm(),
SizedBox(height: kSpacingUnit * 4.0),
SocialMediaLoginWidget(),
],
),
),
),
),
);
Note: You'll need to make sure your EmailSignInForm() and SocialMediaLoginWidget() do not have unbound height.
My guess is your EmailSignInForm() probably utilises a Column. If so set it's mainAxisSize to min.
I'm trying to create a circle in the flutter. I want to add multiple buttons and bound them in a circle like this.
The marked fields are supposed to be buttons and Course 1 is just the text.
I am able to create something like this but it is only string splitted in the button.
Here is my code for this. I'm not getting any idea about how to do this task. I'm new to flutter.
import 'package:flutter/material.dart';
void main(){runApp(MyApp());}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: new AppBar(
title: Text("Student home"),
),
body:Center(
child: Container(
margin: EdgeInsets.all(10),
padding: EdgeInsets.all(10),
width: 200,
height: 200,
child: Center(
child: Text("Course 1 \n Course 2",
style: TextStyle(fontSize: 12.0,
fontStyle: FontStyle.italic,
),
textAlign: TextAlign.center,
),
),
decoration: BoxDecoration(
border:Border.all(width:3),
borderRadius: BorderRadius.all(
Radius.circular(50),
),
color: Colors.yellow,
),
),
)
),
);
}
}
try shape: BoxShape.circle,,
Container(
width: 100,
height: 100,
decoration: BoxDecoration(
border: Border.all(width: 2),
shape: BoxShape.circle,
// You can use like this way or like the below line
//borderRadius: new BorderRadius.circular(30.0),
color: Colors.amber,
),
child:Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('ABC'),
Text('XYZ'),
Text('LOL'),
],
),
),
Output
is this design that you want?
it contain two button and one text widget
body: Center(
child: Container(
margin: EdgeInsets.all(10),
padding: EdgeInsets.all(10),
width: 200,
height: 200,
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
"Course 1",
style: TextStyle(
fontSize: 12.0,
fontStyle: FontStyle.italic,
),
textAlign: TextAlign.center,
),
MaterialButton(
onPressed: () {
//do whatever you want
},
child: Text("Mark Attendance"),
),
MaterialButton(
onPressed: () {
//do whatever you want
},
child: Text("Mark Attendance"),
),
],
),
),
decoration: BoxDecoration(
border: Border.all(width: 3),
borderRadius: BorderRadius.all(
Radius.circular(200),
),
color: Colors.yellow,
),
),
),
There are multiple ways to make the border round. As of now you are using fixed height and width always use greater number for border-radius.
For eg.
when your heigh is 200X200 use 150-200 number for border-radius.
here is the code which works fine when you have fixed height and width of the container.
Note: This works only fine when your heigh and width is fixed for the container because the padding in the code is static.If you want dynamic then please use the screen calculation techniques to make if responsive
Making any widget clickable in the Flutter.
There are a couple of Widgets available to make any widget clickable
Gesture Detector
This widget has many methods including onTap() which means you can attach a callback when the user clicks on the widget. For eg (this is used in your code)
GestureDetector(
onTap: (){}, //this is call back on tap
child: Text("Mark Attendance")
)
InkWell Widget (Note: This widget will only work when it is a child of the Material widget)
Material(
child: InkWell(
onTap: (){},
child: Text("Mark Attendance"),
),
)
Here is the working code.
import 'package:flutter/material.dart';
void main(){runApp(MyApp());}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: new AppBar(
title: Text("Student home"),
),
body:Center(
child: Container(
margin: EdgeInsets.all(10),
padding: EdgeInsets.all(10),
width: 200,
height: 200,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(bottom:40.0,top: 20.0),
child: Text("Course 1"),
),
Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: GestureDetector(
onTap: (){},
child: Text("Mark Attendance")),
),
Padding(
padding: const EdgeInsets.all(8.0),
child:Material(
child: InkWell(
onTap: (){},
child: Text("Mark Attendance"),
),
)
),
],)
],
),
decoration: BoxDecoration(
border:Border.all(width:3),
borderRadius: BorderRadius.all(
Radius.circular(150),
),
color: Colors.yellow,
),
),
)
),
);
} }
Note: Material widget always set the background as white for the text
widget
Thanks, I hope is information was helpfull
I'm attempting to layout some buttons in a flutter app towards the bottom of the screen as seen here:
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
centerTitle: true,
),
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('images/foo.jpeg'),
fit: BoxFit.cover),
),
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 10),
child: _buttonsOne(),
),
Expanded(
child: Text(''),
),
Padding(
padding: EdgeInsets.only(bottom: 10),
child: _buttonsTwo(),
),
],
),
),
);
Counter buttons is setup thusly:
Widget _buttonsTwo() {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
_oneButton(),
_twoButton(),
_threeButton(),
_fourButton()
],
);
}
My problem is two of the buttons are using glyphs that cause them to be just right of center. Prior to attempting this layout I structured raised buttons with columns so that I could use an Align to pull these icons to the left a bit, as seen here for one of the buttons:
Widget _threeButton() {
return RaisedButton(
onPressed: () {},
elevation: 10,
color: Colors.red,
textColor: Colors.white,
padding: EdgeInsets.all(10.0),
child: Column(
children: <Widget>[
Align(
alignment: Alignment(-0.4, 0),
child: Icon(
Class.icon_name,
size: 30,
),
),
Text(
_fooCount.toString(),
style: TextStyle(fontSize: 25),
)
],
),
);
}
And here's the result I'm getting:
As you can see, the icons for the two rightmost buttons are still a little to the right. I've tried using RaisedButton.icon to no avail as it causes the icons to overlap the text, even restructuring them in a row to try and make wider buttons. What am I missing?
Try using Transform widget instead of Align and translate the X axis:
Transform(
transform: Matrix4.identity()..translate(-7.0),
child: Icon(
FiveRingsDB.conflict_political,
size: 30,
),
),
Text(
_militaryCount.toString(),
style: TextStyle(fontSize: 25),
)