I want to make a widget where i can add a progress bar or shapes inside a image.
As in the attachment,
I wrapped the image and the shape inside the Stack widget but when the screen sizes change the position of the widgets change too
Is there any way to achieve this ?
You can set the image as the decoration image of a Container. Then you can use a FractionallySizedBox for the item that should be placed inside the image, and set this widget as the Container's child. You can also use a Flex and set the text and shape (the items inside the image) as its children.
Container(
width: 300,
height: 300,
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(
'https://images.vexels.com/media/users/3/151609/isolated/preview/1e5e087078b86c2491300c61ce46c48c-canning-jar-stroke-icon-by-vexels.png'),
fit: BoxFit.cover),
),
child: Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Align(
alignment: Alignment.bottomCenter,
child: FractionallySizedBox(
heightFactor: 0.6,
widthFactor: 0.6,
child: Flex(
direction: Axis.vertical,
children: <Widget>[
Flexible(
flex: 2,
child: Container(
child: Text(
'50%',
style: TextStyle(fontSize: 24),
)),
),
Flexible(
flex: 8,
child: Container(
child: Image.network(
'https://images.vexels.com/media/users/3/129171/isolated/preview/c3746ad76845f55dda5e6a0d1c81d32a-3-stack-coins-icon-by-vexels.png'),
),
),
],
)),
),
),
),
Result:
If you have screens size issue than use
double height = MediaQuery.of(context).size.height;
double width = MediaQuery.of(context).size.width;
you can get height or width of screen and adjust view according to this.
Related
What widgets should be used to display 3 cartoons at the bottom of this picture and the text at the center responsively for different screen sizes?
Row with spaceEvenly
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
//your images
],
);
https://flutteragency.com/how-to-set-space-between-elements-in-flutter/
There are many ways to do this. It will also depend on what responsive behavior you are looking for. I hope, I understood your specific requirements.
Here is a solution:
class Page extends StatelessWidget {
const Page({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: AspectRatio(
aspectRatio: 16 / 9,
child: Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/bg.png"),
fit: BoxFit.cover,
),
),
child: Stack(children: [
Center(
child: FractionallySizedBox(
widthFactor: .4,
child: FittedBox(
fit: BoxFit.fitWidth,
child: Text(
'Headline text',
style: GoogleFonts.chewy(
textStyle: const TextStyle(
color: Colors.white,
letterSpacing: .5,
),
),
),
),
),
),
Container(
alignment: const Alignment(0, .75),
child: FractionallySizedBox(
widthFactor: .8,
heightFactor: .3,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Image.asset("assets/images/img1.png"),
Image.asset("assets/images/img2.png"),
Image.asset("assets/images/img3.png"),
],
),
),
)
]),
),
),
);
}
}
In this solution,
I use a main Container that will have your image as background.
I then use a Stack to position the headline and the images.
The headline is Centered and defined as a FittedBox inside a FractionallySizedBox. This allows me to have responsivity for the headline too.
Finally, for the list of images, I used a FractionallySizedBox to size the list and an aligned Container to position it within the stack. The images are then spread thanks to the use of MainAxisAlignment.spaceBetween.
So, as you see, I used the following widgets to responsively size and position my Widgets:
Position
Center
Container with the alignment property
Size
FractionallySizedBox
The thing I want to reach is something like this:
These are the main constraints I want to reach:
"text"-s being centered above the lower "button"-s and "thing2" being able to go in between "texts"-s when the screen is short enough.
I want the "button"-s to always be the same height/width (this is easily done by something like SizedBox) and the same distance from the top/bottom .
I want the "thing1" to be x height at max and scale with screen downwards if needed (either by making its texts smaller or making it scrollable, I haven't yet decided, this isn't the main problem).
I want "thing2" to always scale with screen.
When the screen is big enough, I want "thing1" and "thing2" to share the space between them evenly, and each being in the center of its own space.
Right now my layout is the following:
Column: MainAxisAlignment.SpaceBetween, height fixed
Container: height fixed
Row: MainAxisAlignment.SpaceBetween
Button
Button
Container: height fixed
thing1
Container: height calculated based on screen height and other Containers' height
thing2
Container: height fixed
Row: MainAxisAlignment.SpaceBetween
Button
Button
This is of course not all, I tried to include all relevant information about my layout without giving too much information pointlessly.
How would one go about adding the "text"-s above the "button"-s? (I tried Stack, but then I dont't know how to make them appear above the "button"-s while at the same time making "thing2" be above them too.
I managed achieve the things with this code (where MyBox is a simple widget with a colored container with width and height):
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
const double buttonHeight = 35;
const double buttonWidth = 100;
const double textHeight = 40;
const double textWidth = 30;
return Padding(
padding: const EdgeInsets.all(8.0),
child: Stack(
children: [
Align(
alignment: Alignment.topLeft,
child: SizedBox(
width: buttonWidth,
height: buttonHeight,
child: MyBox(Colors.red),
),
),
Align(
alignment: Alignment.topRight,
child: SizedBox(
width: buttonWidth,
height: buttonHeight,
child: MyBox(Colors.yellow),
),
),
Align(
alignment: Alignment.bottomLeft,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: SizedBox(
width: textWidth,
height: textHeight,
child: MyBox(Colors.green),
),
),
SizedBox(
width: buttonWidth,
height: buttonHeight,
child: MyBox(Colors.cyan),
),
],
),
),
Align(
alignment: Alignment.bottomRight,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: SizedBox(
width: textWidth,
height: textHeight,
child: MyBox(Colors.indigo),
),
),
SizedBox(
width: buttonWidth,
height: buttonHeight,
child: MyBox(Colors.blue),
),
],
),
),
Align(
alignment: Alignment.bottomCenter,
child: SizedBox(
width: buttonWidth,
height: buttonHeight,
child: MyBox(Colors.orange),
),
),
Positioned(
left: 0,
top: 0,
right: 0,
bottom: buttonHeight,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Flexible(
fit: FlexFit.loose,
child: MyBox(Colors.purple),
),
Flexible(
fit: FlexFit.loose,
child: MyBox(Colors.brown),
),
],
),
),
],
),
);
}
}
TLDR: I used a Stack widget to hold my other widgets, and Align widget to align (duh) my widgets in the Stack.
I used a Column to center my texts above my lower buttons. "mainAxisAlignment: MainAxisAlignment.end" was important so this column is at the bottom and not at the topside.
Finally I wrapped the Stack in a Padding.
I have these three containers. That the first one needs to grow to cater for the children that will be in it. The second one could have a fixed height say a flex factor of 1, while the third one has a fixed height too say flex of 2. The whole of this screen can be scrollable. It actually has to be scrollable since the children of the first container can be a lot.
Note: the children of the first container will have a fixed height, the container will house a listview or column which will have fixed height children, say containers each of 50.0. How do I achieve this, especially the 'growability' of the first container, while maintaining the heights of the other containers.
What I have currently is
SingleChildScrollView(
child: Container(
height: MediaQuery.of(context).size.height,
child: ListView(
children: [
Flexible(
flex: 1,
child: Container(
color: Colors.blueAccent[200],
child: Column(children: [
Container(
height: 100.0,
color: Colors.greenAccent[200],
),
Container(
height: 100.0,
color: Colors.purpleAccent[200],
),
Container(
height: 100.0,
color: Colors.orangeAccent[200],
)
]),
)),
Expanded(
flex: 1,
child: Container(
color: Colors.redAccent[100],
),
),
Expanded(
flex: 1,
child: Container(
//height: 120.0,
color: Colors.redAccent[400],
),
),
],
),
),
),
Which just brings up lots and lots of errors, does not matter how I lay it out using flexibles and Expanded widgets. Again, I don't need the first container to scroll internally, it should grow according to the number of children in it, while the rest of the two containers maintain their heights.
You can not user Expanded or Flexible inside a scrollable widget since the child of Expanded will then get a height of infinity and the height of the child of Flexible will not get its parents height to compare with.
You can set the height of the bottom two containers based on the height of the screen.
SingleChildScrollView(
child: Container(
height: MediaQuery.of(context).size.height,
child: ListView(
children: [
Container(
color: Colors.blueAccent[200],
child: Column(
children: [
Container(
height: 100.0,
color: Colors.greenAccent[200],
),
Container(
height: 100.0,
color: Colors.purpleAccent[200],
),
Container(
height: 100.0,
color: Colors.orangeAccent[200],
)
],
),
),
Container(
// 33 % of the screen height
height: .33 * MediaQuery.of(context).size.height,
color: Colors.redAccent[100],
),
Container(
// 33 % of the screen height
height: .33 * MediaQuery.of(context).size.height,
color: Colors.redAccent[400],
),
],
),
),
),
I am using a stack widget to display animations inside a screen. I am using only 70% of the screen and the rest I have kept it unused. I want to display something else there. When I am wrapping my stack widget inside a column it is giving the error: Bottom Overflowed by Infinite Pixels.
I tried adding a custom height using Container and SizedBox. Also tried using SingleChildScrollView. Still the same error.
Code:
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: whiteColor,
body: Column(
children: [
Stack(
children: <Widget>[
SizedBox(
height: MediaQuery.of(context).size.height * 0.72,
child: FlareActor(
'assets/videos/stars.flr',
alignment: Alignment.center,
fit: BoxFit.cover,
animation: 'Blink',
controller: _controller,
),
),
Container(
child: Transform.scale(
scale: 0.6,
child: FlareActor(
'assets/videos/talking-earth.flr',
alignment: Alignment.center,
fit: BoxFit.cover,
animation: 'activated',
controller: _controller,
),
),
),
Positioned(
left: MediaQuery.of(context).size.width / 3.8,
top: MediaQuery.of(context).size.width / 10,
child: Text(
"Published",
style: GoogleFonts.ptSansNarrow(
color: whiteColor,
fontSize: ScreenUtil().setSp(50),
fontWeight: FontWeight.bold),
),
),
],
),
Text("Test"),
],
),
);
}
}
You need to wrap your stack with a Container first, setting a predefined height. This is because the Stack size relies on its parent.
Here's the official documentation on Stack: https://api.flutter.dev/flutter/widgets/Stack-class.html
So, I have to display an image in a container and some description at the bottom of the container. The image is supposed to fill the entire screen. The image is being fetched from the network.
This is my intial approach
Stack(
fit: StackFit.expand,
children: <Widget>[
Container(
child: ClipRRect(
child: Image.network(category.imageURL,
height: maxHeight * 1, fit: BoxFit.cover),
),
),
Align(
alignment: Alignment.bottomLeft,
child: getNameAndDeleteSection(context),
)
],
),
),
where getNameAndDeleteSection is basically this
return Container(
color: Colors.yellow,
margin: EdgeInsets.fromLTRB(5, 0, 5, 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
category.name,
maxLines: 1,
style: TextStyle(color: Colors.white),
),
Spacer(),
IconButton(
icon: Icon(Icons.delete, size: 18.0, color: Colors.white,),
onPressed: () {
deleteTap(category);
},
)
],
),
);
}
When the network image is loaded, it hides the yellow container , but keeps the children. What I want is the image to remain at the background and the yellow container to remain above it. The idea is that the yellow container will have a transparent color of sorts , to make it look floating on the image.
The max height is the height provided by the listView. I'm trying to make the UI adaptive. Any help?
Why not puting your image as a BoxDecoration in your container like this:
Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(url), fit: BoxFit.cover,
),
),
),
Align(
alignment: Alignment.bottomLeft,
child: getNameAndDeleteSection(context),
)
],
),
Instead of using a Container that always seems to get hidden by the Network Image, I decided to use Card that will envelop the container. And it worked.
So, the change was done in the getNameAndDeleteSection and basically wrapped the entire code in a Card. And bingo, it worked.