Related
I want my column to be scrollable and I cannot use a Listview as I want the children in Column view to be spaced evenly. Having said that, I want my column to be scrollable. Placing the Column in SingleChildSCrollView, my entire screen becomes blank. Can anyone please suggest me a good option to make my column scrollable without using listview/singlechildscrollview.
The actual code in which I am facing this issue is too big to trace the real problem. I am providing a sample code which highlights the issue that I am facing. Here is my code:
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
backgroundColor: Colors.red,
title: Text(
"Beverages",
),
),
body: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Flexible(
flex: 3,
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Container(
height: 150.0,
decoration: BoxDecoration(
color: kWhiteColor,
borderRadius: BorderRadius.circular(3.0),
boxShadow: [
BoxShadow(
color: Colors.grey[400],
blurRadius: 3.0,
spreadRadius: 1.0,
offset: Offset(2, 2),
)
],
),
),
),
),
Flexible(
flex: 3,
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(10.0),
child: Container(
height: 150.0,
decoration: BoxDecoration(
color: kWhiteColor,
borderRadius: BorderRadius.circular(3.0),
boxShadow: [
BoxShadow(
color: Colors.grey[400],
blurRadius: 3.0,
spreadRadius: 1.0,
offset: Offset(2, 2),
)
],
),
),
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Container(
height: 150.0,
decoration: BoxDecoration(
color: kWhiteColor,
borderRadius: BorderRadius.circular(3.0),
boxShadow: [
BoxShadow(
color: Colors.grey[400],
blurRadius: 3.0,
spreadRadius: 1.0,
offset: Offset(2, 2),
)
],
),
),
),
],
)),
Flexible(
flex: 4,
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Container(
height: 150.0,
decoration: BoxDecoration(
color: kWhiteColor,
borderRadius: BorderRadius.circular(3.0),
boxShadow: [
BoxShadow(
color: Colors.grey[400],
blurRadius: 3.0,
spreadRadius: 1.0,
offset: Offset(2, 2),
)
],
),
),
),
),
],
),
),
);
You can’t use MainAxisAlignment.spaceEvenly when you have your Column inside a SingleChildScrollView. Why this? You're trying to scroll, but your height is somehow infinite and how would you space your children evenly in an infinite space? The same applies when using Flexible widgets. The way to have things scrollable would be if you use either a ListView or a Column inside a SingleChildScrollView. There are other widgets too, but they follow the same logic. I would recommend: you keep your Column wrapped in a SingleChildScrollView and place SizedBox widgets between components to have them evenly separated. Another option would be to use a ListView.builder and place a SizedBox after the Widget to be built. In that way you should be able achieve what you're looking for.
So, about your code: I deleted this spaceEvenly enum because of the reason above. After that, I ran your code and I obtained this:
RenderFlex children have non-zero flex but incoming height constraints
are unbounded
That is the thing with the infinite space I told you the Flexibles are trying to take but they can’t. I also deleted them. So how could you give your Widgets desired size? I would use Containers with static height and inside them, there is where I could then use Expanded or Flexible widgets. If you want something scrollable but don’t want it to occupy the whole screen, try using a Container with static height and inside it a ListView.builder.
i have tried many solution but i couldn't get what i want.
https://stackoverflow.com/a/56744034/4862911 i applied in this answer but couldn't get correct response. There is still shadow top of container. How can i achieve it?
and also i have tried to surround my widget with Material . but still can't solve the problem.
Material(
elevation: 5,
child: Container(
height: 50,
child: _buildEloAndLevel(),
),
),
Material(
elevation: 5,
child: Container(
height: 50,
child: _buildEloAndLevel(),
// add boxShadow
decoration: BoxDecoration(
boxShadow: [
color: Colors.black54,
blurRadius: 15.0,
],
),
),
),
This will create a shadow of 15 units arounds the Container. Now, the shadow can be moved with the offset property. Since, we don't want shadow on top, we can move it down by 15 units.
Material(
elevation: 5,
child: Container(
height: 50,
child: _buildEloAndLevel(),
// add boxShadow
decoration: BoxDecoration(
boxShadow: [
color: Colors.black54,
blurRadius: 15.0,
offset: Offset(0, 15), // horizontally move 0, vertically move 15,
],
),
),
),
I don't know if other examples are really setting a shadow for only bottom, but here is a know solution:
Container(
height: 50.0,
decoration: BoxDecoration(
boxShadow: <BoxShadow>[
BoxShadow(
color: Colors.black54,
blurRadius: 20.0,
spreadRadius: -20.0,
offset: Offset(0.0, 25.0),
)
],
color: Colors.red,
),
),
Set the blur of the shadow with blurRadius and then set the spreadRadius to negative the blurRadius then use the dy property of the Offset() constructor, you set it to positive values to control the shadow bottom.
All you need to do is playing around with your offset's value. And I think you don't need to wrap it with Material.
Offset is the displacement of the shadow from the box. It requires 2 double-types values, Offset(x, y);
Example:
Container(
height: 50.0,
decoration: BoxDecoration(
boxShadow: <BoxShadow>[
BoxShadow(
color: Colors.black54,
offset: Offset(15.0, 20.0),
blurRadius: 20.0,
)
],
color: Colors.red,
),
),
TIPS FROM ME: To make sure the shadow doesn't show up in the top of your container, make sure your blur radius is not bigger than your Offset's y-value.
I am trying to add a shadow to only the right side of of my container widget using the boxShadow parameter in the BoxDecoration widget.
new Container(
decoration: BoxDecoration(
color: Colors.grey.withOpacity(0.5),
boxShadow: [
BoxShadow(
blurRadius: 5.0
),
],
),
),
This code works but adds a shadow to every possible side of the container. I would like to have it only be on the right side.
You can set the offset property of BoxShadow. It is defined as Offset(double dx, double dy). So, for example:
boxShadow: [
BoxShadow(
blurRadius: 5.0,
offset: Offset(3.0, 0),
),
],
This will cast a shadow only at 3 units to the right (dx).
boxShadow property of BoxDecoration takes a list of BoxShadow, so you can pass solid BoxShadow to the rest of the sides and corners with background color. Note that a small shadow remains at the corners, but hey!... Life is not perfect ;)
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(title: Text('Shadow Test')),
body: Center(
child: Container(
width: 200,
height: 200,
decoration: BoxDecoration(
color: Colors.blueAccent,
boxShadow: [
BoxShadow(blurRadius: 8.0),
BoxShadow(color: Colors.white, offset: Offset(0, -16)),
BoxShadow(color: Colors.white, offset: Offset(0, 16)),
BoxShadow(color: Colors.white, offset: Offset(-16, -16)),
BoxShadow(color: Colors.white, offset: Offset(-16, 16)),
],
),
),
),
);
Screenshot
This is one way:
Container(
width: 230,
height: 200,
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(),
child: Container(
margin: EdgeInsets.only(right: 30), // ***
decoration: BoxDecoration(
color: Colors.blue,
boxShadow: [
BoxShadow(
color: Colors.red,
blurRadius: 20,
spreadRadius: 8,
)
],
),
),
)
*** : whichever side you give margin to, that side will show the shadow. Giving margin to multiple sides also works.
A box shadow is actually just a tinted, blurred and shifted version of the parent object which is then rendered underneath it. That's why having a box shadow just on one side isn't trivial.
The most straight forward solution is to cut off the shadow on the sides where you do not need it. In Flutter this can be nicely achieved via the CustomClipper class. The example below clips the entire shadow of the object except on the sides where we define a padding (which should be at least as large as the overlapping shadow).
/// Clips the given object by its size.
/// The clip area can optionally be enlarged by a given padding.
class ClipPad extends CustomClipper<Rect> {
final EdgeInsets padding;
const ClipPad({
this.padding = EdgeInsets.zero
});
#override
Rect getClip(Size size) => padding.inflateRect(Offset.zero & size);
#override
bool shouldReclip(ClipPad oldClipper) => oldClipper.padding != padding;
}
ClipRect(
clipper: const ClipPad(
padding: EdgeInsets.only(left: 30, top:30)
),
child: Container(
width: 200,
height: 200,
decoration: const BoxDecoration(
color: Colors.black,
boxShadow: [
BoxShadow(
color: Colors.red,
blurRadius: 20,
)
]
)
)
);
Note: You might want to use a different Clipper-Widget and CustomClipper for shapes other than rectangles like for example ClipRRect or ClipPath.
Note that MyShadowSize = spreadRadius + x/y Offset.
Example:
If spreadRadius: 1, offset: Offset(0, 0) => 4 sides is MyShadowSize has 1 + 0 = 1.
If you want only bottom shadow = 1, you can add: spreadRadius: 0, offset: Offset(0, 1),
Explain: Current y offset = 1, => MyShadowSize bottom = 1, MyShadowSize top = -1 (because y move down) => MyShadowSize top not show.
To avoid those ugly edges from the other answers here, you can do it this.
final oneSideShadow = Padding(
padding: const EdgeInsets.only(left: 30, right: 30, top: 30),
child: Container(
decoration: BoxDecoration(
color: Colors.green,
borderRadius: borderRadius,
boxShadow: [
BoxShadow(
color: Colors.red.withOpacity(0.95),
blurRadius: 26,
offset: const Offset(0, 2), // changes position of shadow
),
],
),
),
);
return Container(
width: 200,
height: 200,
child: Stack(
children: [
oneSideShadow,
Container(
decoration: const BoxDecoration(
color: Colors.yellow,
),
),
],
),
);
You can get pretty wild results with this, e.g. if you modify the code above, and put row+expanded childs with different shadows there.
Adding shadow to a single side is very hard since it's a shifted and blurred version of the parent widget. I tried all the other ways but didn't work really well.
for longer shadow.
I also found one other way is by use Stack Widget to cover the other sides. If you don't have anything near that widget. if you have a widget near it, you can use that widget to cover the shadow.
Please refer to the code below.
Stack(alignment: Alignment.topCenter, children: [
Padding(
padding: EdgeInsets.only(top: 14),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Color(0xff000000).withOpacity(0.1),
spreadRadius: 0,
blurRadius: 10,
offset: Offset(0.0, 4),
// // changes position of shadow
),
],
),
child: TabBar(
indicatorColor: Color(0xffFF7000),
unselectedLabelColor: Color(0xff818898),
labelColor: Color(0xffFF7000),
tabs: [
Tab(
child: Text(
'Tab 0'
style: TextStyle(
fontSize: UiSizeUtils.getFontSize(14),
fontWeight: FontWeight.w600),
),
),
Tab(
child: Text(
'Tab 1'
style: TextStyle(
color: Color(0xff8D99BB),
fontSize: UiSizeUtils.getFontSize(14),
fontWeight: FontWeight.w600),
),
),
],
controller: _tabController,
indicatorSize: TabBarIndicatorSize.tab,
),
),
),
Container(
width: double.infinity,
height: UiSizeUtils.getHeightSize(16),
color: Colors.white,
)
]),
This is how I added the shadow for the bottom only for the tab view and this works best for my use case when compared with the other method mentioned above.
I have a simple screen with a container about 100 in height and with blue color. I want to add a shadow or elevation at the bottom of the container.
This is my code below
import 'package:flutter/material.dart';
import 'package:finsec/utils/strings.dart';
import 'package:finsec/utils/dimens.dart';
import 'package:finsec/utils/colors.dart';
void main() {
runApp(new IncomeFragment());
}
class IncomeFragment extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Stack(
children: <Widget>[
new Container(
height: margin_100dp,
color: colorPrimary,
),
new Container( //container to overlay on top of blue container
alignment: Alignment.topCenter,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
zero_amount,
style: TextStyle(color: white, fontSize: 40.0, fontWeight: FontWeight.bold)
),
],
),
)
],
);
}
}
can someone help me to add a shadow or elevation at the bottom of my blue container?
see image below. shawdow should be in place in the red circle
thanks in advance
You can reuse the first container that you have in your Stack, the container has a property called decoration and it accept a widget of kind BoxDecoration, as you can see in this link: BoxDecoration
Inside this widget you can use the boxShadow property to give to your container a custom shadow, try the next code:
new Container(
height: margin_100dp,
decoration: BoxDecoration(
boxShadow: <BoxShadow>[
BoxShadow(
color: Colors.black54,
blurRadius: 15.0,
offset: Offset(0.0, 0.75)
)
],
color: colorPrimary
),
),
Or you can wrap your Container widget with a Material widget which contains an elevation property to give the shadowy effects.
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Material(
elevation: 15.0,
child: Container(
height: 100,
width: 100,
color: Colors.blue,
child: Center(child: Text("Material",style: TextStyle(color: Colors.white),)),
),
),
SizedBox(width: 100,),
Container(
height: 100,
width: 100,
decoration: BoxDecoration(
boxShadow: <BoxShadow>[
BoxShadow(
color: Colors.black54,
blurRadius: 15.0,
offset: Offset(0.0, 0.75)
)
],
color: Colors.blue
),
child: Center(child: Text('Box Shadow',style: TextStyle(color: Colors.white))),
),
],
),
),
Image:
Difference between two widgets is shown above. Hope this helps!!!
Yes, BoxShadow can solve the problem but instead of manually adding the list of BoxShadow, there is a handy map in flutter call kElevationToShadow which map elevation keys to pre-defined list of BoxShadow. It is also defined based on the material design elevation.
Container(
height: 60.0,
decoration: BoxDecoration(
boxShadow: kElevationToShadow[4],
color: Theme.of(context).bottomAppBarColor,
),
child: ...
);
Container(
margin: EdgeInsets.only(bottom: 7),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
boxShadow: kElevationToShadow[2], // Use This kElevationToShadow ***********
),
child: Center(child: Text('With BoxShadow')),
),
Material( // Using Material Widget ***********************
elevation: 5,
borderRadius: BorderRadius.circular(10),
child: Container(
margin: EdgeInsets.only(bottom: 7),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
),
child: Center(child: Text('With BoxShadow')),
),
),
use the Container Shadow as below:
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.black,
offset: Offset(20.0, 10.0),
blurRadius: 20.0,
spreadRadius: 40.0,
),
],
),
Controll the blurRadius and the SpreadRadius depending on your needs
if you want a container to have shadow only top
boxShadow: [
BoxShadow(
color: Color.fromARGB(255, 218, 218, 218),
blurRadius: 10.0, // soften the shadow
spreadRadius: 0.0, //extend the shadow
offset: Offset(
0.0, // Move to right 10 horizontally
-15.0, // Move to bottom 10 Vertically
),
)
],
You can add several BoxShadow to show the shadow you need,
with OffSet propertie you can move the shadow.
boxShadow: [
BoxShadow(
color: Colors.blue,
offset: Offset(0, 8), // hide shadow top
blurRadius: 5),
BoxShadow(
color: Colors.white, // replace with color of container
offset: Offset(-8, 0), // hide shadow right
),
BoxShadow(
color: Colors.white, // replace with color of container
offset: Offset(8, 0), // hide shadow left
),
],
I have a Container with a BoxShadow decoration at the top of a page, and below the Container is a ListView with a number of Cards in it. I want the top Container to have a drop shadow that appears in front of the items in the ListView, but this is what I get:
The drop shadow seems to appear behind the Cards instead of in front of it. This is the code:
Widget _buildBody(BuildContext context, ChecklistModel model){
return Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
decoration: BoxDecoration(
color: Colors.red.shade200,
boxShadow: [BoxShadow(
color: Colors.red.shade200,
offset: Offset(0, 10),
blurRadius: 10,
spreadRadius: 10
)]
),
child: ListTile(
title: Text(''),
)
),
Expanded(child: Padding(
padding: const EdgeInsets.all(10),
child: _buildCheckpointListView(context, model))
)
],
)
);
}
I also tried replacing the Container with a Card, but that didn't work either.
It is happening because since you are using an Expanded widget inside Column, it is taking up all the available space on the screen and hence it looks like it is overlapping the Container but actually it's just overlapping the shadow.
Instead of a Column widget, use a Stack to show the Container above the ListView.
You can use Positioned widget to position the child widgets of the Stack.
But in this case, make sure you put the Container code after the ListView code so that it would always be on top.
Example:
Stack(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(10),
child: _buildCheckpointListView(context, model)
),
Positioned(
top: 0.0, //To align Container at the top of screen
left: 0.0,
right: 0.0,
child: Container(
decoration: BoxDecoration(
color: Colors.red.shade200,
boxShadow: [
BoxShadow(
color: Colors.red.shade200,
offset: Offset(0, 10),
blurRadius: 10,
spreadRadius: 10
)]
),
child: ListTile(
title: Text(''),
)
),
),
]
)
You can also wrap you ListView inside a Positioned widget if you want to provide a certain margin from top.
Give a bottom margin to the container to introduce some empty space between container and bottom siblings. Like this :
Container(
margin: EdgeInsets.only(bottom: 20),
decoration: BoxDecoration(
color: Colors.red.shade200,
boxShadow: [BoxShadow(
color: Colors.red.shade200,
offset: Offset(0, 10),
blurRadius: 10,
spreadRadius: 10
)]
),
child: ListTile(
title: Text(''),
)
),