I try to make my first app with Flutter.
I have a question i make this custom bottom bar:
Are there better method for make this effect or similar effect?
Is it correct this method with stack and row?
Thanks u and good coding!
Container bottom(Size size) {
double totalElement = size.width / 3;
return Container(
height: size.width * 0.15,
//color: GS.mainColor,
child: Stack(
alignment: Alignment.bottomLeft,
children: [
//LONG ELEMENT
Positioned(
child: Container(
width: totalElement*3,
height: GS.heightBottomElement,
decoration: BoxDecoration(
color: Colors.green,
borderRadius: BorderRadius.only(
topRight: Radius.circular(20),
topLeft: Radius.circular(20),
)
),
)
),
//FIRST ELEMENT
Positioned(
child: Container(
height: GS.heightBottomElement,
width: totalElement*2,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.only(
topRight: Radius.circular(20),
topLeft: Radius.circular(20),
)
),
)
),
//FIRST ELEMENT
Positioned(
child: Container(
height: GS.heightBottomElement,
width: totalElement,
decoration: BoxDecoration(
color: Colors.orange,
borderRadius: BorderRadius.only(
topRight: Radius.circular(20),
topLeft: Radius.circular(20),
)
),
)
),
],
),
);
}
You could extract the Positioned elements into a separate stateless widget, in that way you use the DRY method, and your code will look nicer and cleaner, with less repeated code.
It would look like this:
Container bottom(Size size) {
double totalElement = size.width / 3;
return Container(
height: size.width * 0.15,
//color: GS.mainColor,
child: Stack(
alignment: Alignment.bottomLeft,
children: [
//LONG ELEMENT
MyCutomPositioned(height: blabla, width: blabla, color: blabla),
//FIRST ELEMENT
MyCutomPositioned(height: blabla, width: blabla, color: blabla),
//SECOND ELEMENT
MyCutomPositioned(height: blabla, width: blabla, color: blabla),
],
),
);
}
Related
I try to create using stack and other container but I am getting normal line.
You can try to make the color of the Container transparent and make the background color of the Scaffold instead.
That way the line of the container will disappear.
This code is just for the demo you will need to update it as per your requirement :
Scaffold(
body: Center(
child: Column(
children: [
SizedBox(height: 50),
Container(
height: 50,
width: 250,
decoration: BoxDecoration(
color: Colors.blueGrey,
borderRadius: BorderRadius.circular(30),
),
),
Container(
height: 100,
width: double.infinity,
color: Colors.blueGrey,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
height: 100,
width: Get.width * 0.43,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(20),
topRight: Radius.circular(20),
),
color: Colors.white,
),
),
Icon(Icons.calendar_month),
Container(
height: 100,
width: Get.width * 0.43,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(20),
topLeft: Radius.circular(20),
),
color: Colors.white,
),
),
],
),
),
Container(
height: 50,
width: 350,
decoration: BoxDecoration(
color: Colors.blueGrey,
borderRadius: BorderRadius.circular(30),
),
),
],
),
),
);
I'm trying to achieve something like this in flutter:
This is my attempt to do that
class ContainerWidget extends StatelessWidget {
final Widget child;
final double width, height;
late List<Color>? gradiantColors;
ContainerWidget({
Key? key,
required this.child,
required this.height,
required this.width,
this.gradiantColors,
}) : super(key: key);
#override
Widget build(BuildContext context) {
var border = BorderRadius.only(
topRight: Radius.circular(70),
topLeft: Radius.circular(8),
bottomLeft: Radius.circular(8),
bottomRight: Radius.circular(8),
);
return Container(
decoration: BoxDecoration(
color: gradiantColors == null ? Colors.white : null,
borderRadius: border,
boxShadow: [
BoxShadow(
color: Colors.grey.shade300,
offset: Offset(0, 1),
blurRadius: 30,
spreadRadius: 5,
),
],
gradient: gradiantColors != null
? LinearGradient(
colors: gradiantColors!,
begin: Alignment.topLeft,
end: Alignment.bottomRight,
)
: null,
),
width: width,
height: height,
child: Stack(
children: [
Positioned(
top: -40,
left: -20,
child: Container(
decoration: BoxDecoration(
color: Colors.red.shade100.withOpacity(0.2),
shape: BoxShape.circle,
),
width: 100,
height: 100,
),
),
Positioned(
child: Icon(
Icons.abc_rounded,
size: 40,
),
),
child
],
),
);
}
}
this is the output
However, I've two problems:
The circle on top leak out over the rounded corner, I tried to solve that with the ClipRRect, but it clipped also the shadow of the container.
Icon (or the image) cannot be placed above the top portion of the container.
Any ideas ?
Like this (put this inside your widget class):
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Stack(
clipBehavior: Clip.none,
children: [
Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(blurRadius: 20,
color: Colors.orange.withOpacity(0.5),
offset: const Offset(0.0, 8.0)
)
],
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(100),
bottomLeft: Radius.circular(20),
bottomRight: Radius.circular(20)
)
),
child: ClipRRect(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(100),
bottomLeft: Radius.circular(20),
bottomRight: Radius.circular(20)
),
child: Stack(
children: [
Container(
width: 200,
height: 300,
color: Colors.orange
),
Positioned(
top: -50,
left: -40,
child: ClipOval(
child: Container(
width: 150,
height: 150,
color: Colors.white.withOpacity(0.25)
)
)
)
]
)
)
),
Positioned(
top: -40,
left: 20,
child: Container(
width: 80,
height: 80,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(25),
boxShadow: [
BoxShadow(blurRadius: 10, color: Colors.black.withOpacity(0.2), offset: const Offset(0.0, 5.0))
]
)
)
)
]
)
)
);
}
which then ends up looking like this:
The top white Container is just a placeholder for what your image could look like. I'd suggest then using a PNG already with the shadow integrated if you'll be using pictures like that.
Let me know if that's what you're trying to accomplish and adjust to your needs.
I need to implement this widget of an image on top and a container with a text underderneath.
The thing is that the container has a three sided border with rounded bottom corners. But flutter won't allow me to have border radius with a non-uniform Border.
here is my code:
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
AspectRatio(
aspectRatio: 1,
child: ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(4),
topRight: Radius.circular(4),
),
child: Container(
width: MediaQuery.of(context).size.width / 2,
child: CachedNetworkImage(
imageUrl: topic.image,
placeholder: (_, __) => ImagePlaceholder(),
height: (MediaQuery.of(context).size.width / 2) * 1.11,
fit: BoxFit.fill,
),
),
),
),
Expanded(
child: Container(
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(4),
bottomRight: Radius.circular(4)),
border: Border(
bottom: BorderSide(
width: 1, color: Theme.of(context).dividerColor),
right: BorderSide(
width: 1, color: Theme.of(context).dividerColor),
left: BorderSide(
width: 1,
color: Theme.of(context).dividerColor))),
child: Text(topic.title)),
)
],
)
basically I can't get the top border of the container below my image to be transparent.
and here is the exception I get:
The following assertion was thrown during paint():
A borderRadius can only be given for a uniform Border.
The following is not uniform:
BorderSide.color
BorderSide.width
how can i implement this?
Container alone isn't going to cut it here. You are going to need to come up with some sort of workaround. Here's one such workaround using a combination of Container, ClipRRect, and `Column.
ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Container(
color: Colors.grey,
child: Column(
children: [
Image(...),
Expanded(
child: Container(
width: double.infinity,
height: double.infinity,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(bottomLeft: Radius.circular(8), bottomRight: Radius.circular(8)),
),
margin: EdgeInsets.only(left: 4, bottom: 4, right: 4),
child: Text(...),
),
),
],
),
),
),
You will probably want to play with it to get the sizing and layout to look how you want, but that's the general idea.
DartPad example
ClipRRect is what exactly you need to know
ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(15),
topRight: Radius.circular(15),
),
// Your Image
child: Image()
)
Here is the full code for your goal.
Column(
children: [
ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(15),
topRight: Radius.circular(15),
),
child: Image.network(
'imageUrl',
height: 250,
width: 300,
fit: BoxFit.cover,
),
),
Container(
decoration: BoxDecoration(
border: Border.all(
color: Colors.black,
),
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(40.0),
bottomLeft: Radius.circular(40.0),
),
),
width: 300,
padding: EdgeInsets.symmetric(
vertical: 5,
horizontal: 20,
),
child: Text(
'My Text Here',
style: TextStyle(
fontSize: 26,
),
softWrap: true,
overflow: TextOverflow.fade,
),
),
],
),
I am trying to do this card. But I don't know how to the green shape part. Any suggestions?
Inside a row create a container and give it DecorationBox and some radius to upper and bottom left corners and a second child as text. You can modify the following example code according to your needs.
Container(
child: Row(
children: [
Container(
decoration: BoxDecoration(
color: Colors.green,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(5),
bottomLeft: Radius.circular(5))),
height: 20,
width: 20,
),
Text('data'),
],
)),
Exactly how I want it.
class NotificationBanner extends StatelessWidget {
final Radius radius = Radius.circular(10.0);
#override
Widget build(BuildContext context) {
return Container(
child: Row(
children: [
Container(
height: 100,
width: 8,
decoration: BoxDecoration(
color: Colors.green,
borderRadius: BorderRadius.only(
topLeft: radius,
bottomLeft: radius,
),
),
),
Expanded(
child: Container(
height: 100,
decoration: BoxDecoration(
color: kLightBlack,
borderRadius: BorderRadius.only(
topRight: radius,
bottomRight: radius,
),
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: Align(
alignment: Alignment.centerLeft,
child: Text(
'Some pretty message',
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 20.0),
),
),
)),
),
],
),
);
}
}
I'm following the picture below but got some difficulties when I tried to make that white bubble.
I have tried a method using OverFlowBox from another post Flutter mask a circle into a container but I got the circle stuck in the middle of the Container and I don't know why alignment won't help moving it. Here is what I've tried:
return Container(
alignment: Alignment.topCenter,
height: screenHeight/3.5,
width: screenWidth/3.5,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10),
topRight: Radius.circular(60),
bottomLeft: Radius.circular(10),
bottomRight: Radius.circular(10),
),
gradient: LinearGradient(
begin: FractionalOffset.topLeft,
end: FractionalOffset.bottomRight,
colors: [boxColorBegin, boxColorEnd]
),
),
child: ClipRect(
clipBehavior: Clip.hardEdge,
child: OverflowBox(
maxHeight: screenHeight/3.5 +20,
maxWidth: screenWidth/3.5 + 20,
child:Container(
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
),
)
),
),
);
And the result was
Is there any ways to overflow something inside a widget so that it looks like clipped?
Thanks in advance!
I found the way to achieve what I want but am still confused why OverFlowBox can't be aligned. I thought it is because the size of the OverFlowBox is larger than its parent but it still don't work when I changed it to a smaller size.
I used Stack and Positioned widget and set the overflow parameter of the Stack as overflow.clip
Here is the code:
return Container(
height: screenHeight/3.5,
width: screenWidth/3.2,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10),
topRight: Radius.circular(60),
bottomLeft: Radius.circular(10),
bottomRight: Radius.circular(10),
),
gradient: LinearGradient(
begin: FractionalOffset.topLeft,
end: FractionalOffset.bottomRight,
colors: [boxColorBegin, boxColorEnd]
),
),
child: Stack(
overflow: Overflow.clip,
alignment: Alignment.topCenter ,
children: <Widget>[
Positioned(
bottom: screenHeight / 8,
right: screenWidth / 12,
child: Container(
width: screenWidth / 3.5,
height: screenHeight / 3.5,
decoration: BoxDecoration(
color: Colors.white38,
shape: BoxShape.circle,
),
)
)
],
)
)
And the result is
EDIT
Turns out you can just use Container as a clipper with the clipBehavior parameter and use FractionalTranslation widget as child to manipulate the position of the white circle. Thanks to pskink for the simple answer.
Here is the new code
return Container(
alignment: Alignment.topLeft,
clipBehavior: Clip.antiAlias,
height: screenHeight/3.5,
width: screenWidth/3.2,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10),
topRight: Radius.circular(60),
bottomLeft: Radius.circular(10),
bottomRight: Radius.circular(10),
),
gradient: LinearGradient(
begin: FractionalOffset.topLeft,
end: FractionalOffset.bottomRight,
colors: [boxColorBegin, boxColorEnd]
),
),
child: FractionalTranslation(
translation: Offset(-0.25, -0.5),
child: Container(
width: screenWidth / 3.5,
height: screenHeight / 3.5,
decoration: BoxDecoration(
color: Colors.white38,
shape: BoxShape.circle,
),
)
)
);
You can easily accomplish this using ClipRRect as your root container for this widget. Provide it a border radius and it will clip all children and prevent them from painting outside the bounds. You can then use Transform.translate to render a circle and offset it outside its parent.
I created a sample pen for you to try
return ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(8),
bottomLeft: Radius.circular(8),
bottomRight: Radius.circular(8),
topRight: Radius.circular(125),
),
child: Container(
height: 400,
width: 250,
decoration: BoxDecoration(
color: Colors.red,
),
child: Stack(
children: [
Align(
alignment: Alignment.topLeft,
child: Transform.translate(
offset: Offset(-40, -100),
child: Container(
height: 220,
width: 220,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(110)),
color: Colors.white.withOpacity(0.4),
),
),
),
),
],
),
),
);
For more information on ClipRRect and Transform.translate visit the API docs.
you can use padding to move the OverflowBox. you also need to clip the parent Container with ClipRRect
here is your fix (tested and works):
return ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10),
topRight: Radius.circular(60),
bottomLeft: Radius.circular(10),
bottomRight: Radius.circular(10),
),
child: Container(
alignment: Alignment.topCenter,
height: screenHeight / 3.5,
width: screenWidth / 3.5,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10),
topRight: Radius.circular(60),
bottomLeft: Radius.circular(10),
bottomRight: Radius.circular(10),
),
gradient: LinearGradient(
begin: FractionalOffset.topLeft, end: FractionalOffset.bottomRight, colors: [boxColorBegin, boxColorEnd]),
),
child: ClipRect(
clipBehavior: Clip.hardEdge,
child: Padding(
padding: const EdgeInsets.only(right: 130, bottom: 150),
child: OverflowBox(
maxHeight: screenHeight / 3.5 + 20,
maxWidth: screenWidth / 3.5 + 20,
child: Container(
decoration: BoxDecoration(
color: Colors.white.withAlpha(80),
shape: BoxShape.circle,
),
)),
),
),
),
);