flutter icon as background with overflow - flutter

I'm trying to recreate the weather app design from this link UI design. However i'm stuck at creating the huge Icon that is overflowing in the background. I tried to use a stack and add an Icon widget with very big size. However, the icon will change its position when the size is changed. So it moves from the center. Any idea on how to get the background result as in the design?
Edit:
I tried the code below. However the icon will move if the screen size of the device changes. Is there away to have this look the same on every screen size?
Stack(
children: [
Positioned(
left: -250,
top: -100,
child: Icon(
Icons.ac_unit,
size: 900,
color: Colors.white.withOpacity(0.5),
),
),
Which gives me the result below.

Use the widget: OverflowBox
The Flutter documentation explains OverflowBox as:
A widget that imposes different constraints on its child than it gets from its parent, possibly allowing the child to overflow the parent.
Example:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Overflow Box',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
backgroundColor: Colors.blue,
body: Stack(children: [
OverflowBox(
// Specify the maxWidth and maxHeight and it works
// regardless of orientation.
maxWidth: 800,
maxHeight: 800,
child: Icon(
Icons.ac_unit,
size: 800,
color: Colors.black.withAlpha(80),
),
),
]),
),
);
}
}
Image of the code in action:

Using Stack is fine. Did you use Positioned or Align to wrap the Icon widget, to control its position?
For example, your widget hierarchy could be something like: Stack > Align > Icon.
In the Align widget, you can specify how it aligns in the Stack. The values are (x, y) ranging from -1 to +1, with 0 being the center. For example, you can use alignment: Alignment(0, -0.5) to make it center horizontally, and 50% towards the top on the vertical axis.

if you will use Positioned widget, you can actually positioned based on screen height and width and then warp in FractionalTranslation to center it from its given size,
lets calculate with simple way :
code :
return Stack(
children: [
Positioned(
left: MediaQuery.of(context).size.width * 0.35,
top: MediaQuery.of(context).size.height * 0.4,
child: FractionalTranslation(
translation: const Offset(-0.5, -0.5),
child: child()),
)
],
);

I like the answer that #Tor-Martin Holen suggested, but I would adjust the maxWidth and size attributes to MediaQuery.of(context).size.width to adjust to different screens.

Related

How can Flutter Widgets be sized relatively to each other?

I'm a couple days into learning Flutter, and I keep running into a situation where I want to scale a collection of widgets (aka a Row, Column, Stack, etc) down when the screen shrinks, akin to what Flexible() does. Except unlike Flexible(), I want all children to scale down when the container shrinks, not just the largest elements. Consider this example of a Column() (green) with two children: a red child matching its parent's width, and a blue child with half the parent's width:
In the above case, if the green Column() were to be constrained such that its width was less, you would end up with something like such:
However, what I am wanting is for each of the child elements (red/blue) to scale their width/height relative to each other, like this:
How can I accomplish this?
In the specific Column() case I illustrated above, my workaround was to add a Row() containing the blue widget as well as a Padding(), both with equal flex properties, so that when the Column() shrunk the blue element scaled correctly. I feel like this is a hack though, and wouldn't be as feasible if I had many elements with differing widths/alignments. It would be a nightmare to add one Padding() for left/right aligned elements and two for centered ones. Is there a better way?
I'd also like to know of a similar solution for using Stack()s. Using the Positional() element seems to set the width/height in a way that the Stack() crops any overflow. It'd be nice to have a Stack() that scales all its children the same, just like if it was a single image, and similar to my Column() example above.
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: const MyStatelessWidget(),
),
);
}
}
class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({super.key});
#override
Widget build(BuildContext context) {
return SizedBox.expand(
child: FractionallySizedBox(
widthFactor: 0.5,
heightFactor: 0.5,
alignment: FractionalOffset.center,
child: DecoratedBox(
decoration: BoxDecoration(
border: Border.all(
color: Colors.blue,
width: 4,
),
),
),
),
);
}
}
FractionallySizedBox Widget is a widget that sizes its child to a fraction of the total available space. To make it easy to understand how FractionallySizedBox works
You can have a look at FractionallySizedBox class, you can specify the widthFactor and heightFactor e.g. 0.5 so that it is always half the size of the parent container.
Example:
Flexible(
child: FractionallySizedBox(
widthFactor: 0.5,
heightFactor: 0.5,
alignment: FractionalOffset.centerLeft,
child: Container(
color: Colors.blue),
),
),

how to give a widget, a specific width according to its parent - Flutter

there is a scenario that i have a circle and inside that circle i want to show some text. Both items are in a scrollable listview. i want to calculate the width of the parent and then give with to the inner children to be placed and shouldn't move backward or forward from its outer parent circle widget.
i have used stack widget to do so which works fine on a single device or screen but what about other screen sizes?
any suggestion according to this?
I asked yesterday the same concept question:
the FractionallySizedBox is super useful on those cases, it gives the width / height of a children based on the width / height of the parent:
class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ParentCircle(
height: 250,
width: 250,
color: Colors.red,
child: FractionallySizedBox(
widthFactor: .5,
heightFactor: .5,
alignment: FractionalOffset.center,
child: ChildCircle(),
),
),
),
),
);
}
}
this will give the ChildCircle a 50% width and 50% height of the ParentCircle

Why doesn't Container respect the size it was given?

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: TestCode(),
);
}
}
class TestCode extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
width: 200,
height: 100,
color: Colors.red,
child: Container(
width: 100,
height: 100,
color: Colors.green,
),
);
}
}
In fact, this code is very simple. I just want to display a 200 * 100 red cube and a 100 * 100 green cube.
But the running effect is full screen green? Why is that?
Next, I added a Scaffold toTestCode, as follows
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Scaffold(body: TestCode()),
);
}
The effect again seems to be closer, showing a 200 * 100 green cuboid? Why is that?
Next, I added an alignment to the first Container, as follows
#override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.topLeft,
width: 200,
height: 100,
color: Colors.red,
child: Container(
width: 100,
height: 100,
color: Colors.green,
),
);
}
Finally achieved the desired effect, why is this, who can explain, I must figure this out.
This is caused by what we call "tight vs loose constraints" in Flutter.
TD;DR, width/height are tight constraints (in the sense that there's only a single possibility).
But you never specified to the framework how to switch between the tight constraint of 200x200 specified by the parent, to the tight constraint of 100x100 of the child.
This cause a constraint conflict. Both widgets have a single possibility, and there's nothing that allows both to live together (like an alignment).
In that situation, the constraints of the parent always win, and we therefore end up with a 200x200 square where the child fills its parent.
If that is not what you want; then you should transform your "tight" constraint into a "loose" constraint.
A loose constraint is a constraint that offer the child multiple possibilities, which usually remove the conflict.
The most common way to introduce a loose constraint is to use Alignment (or Center or the alignment property of Container).
As such, if you write:
Container(
width: 200,
height: 100,
color: Colors.red,
child: Center(
child: Container(
width: 100,
height: 100,
color: Colors.green,
),
),
);
then in that situation, Center will act as a middle ground between the parent and child Container.
It will understand that both wants a different size. And it will solve the conflict by aligning the child in the parent.
Now, why is this desired you may ask? Why can't Flutter implicitly add an alignment here?
That is because in many situations, this behavior is desired.
Basically, this ensures that there's always a way to customize the size of something (without having to expose tons of properties on all widgets).
Take RaisedButton as an example. It doesn't expose anything to change its size, but we may want it to fill the screen.
In that situation we'd write:
SizedBox.expand(
child: RaisedButton(...),
)
Because of the behavior we explained previously with the parent overriding the child size when there's a conflict, this code will produce a RaisedButton that properly fills the screen.
height and width properties getting overrided. You can have more info about box constraints on this article:
Dealing with box constraints
Flutter has bunch of layout widgets that can get the job done. In your case you gave Container to the home property of MaterialApp. This set the minimum size of the Container to the screen size. MaterialApp wants his child to fill all the screen in order to prevent any black pixels. This is an expected behaviour. However you can use a layout widget that can break this constraint, it may be Center , FittedBox or else.
An example with FittedBox:
class TestCode extends StatelessWidget {
#override
Widget build(BuildContext context) {
return FittedBox(
fit: BoxFit.scaleDown,
child: Container(
width: 200,
height: 100,
color: Colors.red,
child: FittedBox(
fit: BoxFit.scaleDown,
child: Container(
width: 100,
height: 100,
color: Colors.green,
),
),
),
);
}
}
Output:
Always remember that the container by default takes the dimensions of the parent, and it's a good practice to wrap all your elements/widgets in a root top level Container and then wrap each container in the widget tree with widgets that position the desired Container (Center can be such a widget)
An easy work-around solution for your problem would be:
// The root container
Container(
//Center for positioning the child Container properly
child: Center(
child: Container(
height: 100,
width: 200,
color: Colors.red,
//Center for positioning the child Container properly
child: Center(
child: Container(
height: 100,
width: 100,
color: Colors.green,
),
),
),
),
),
Just change your code into this. You have to specify alignment.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: TestCode(),
);
}
}
class TestCode extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
width: 200.0,
height: 100.0,
color: Colors.red,
alignment: Alignment.center, // where to position the child
child: Container(
width: 100.0,
height: 100.0,
color: Colors.green,
),
);
}
}

How to make relative layout in flutter app

Please see this image -https://ibb.co/YpjJsLZ
In above image how can I place burger image to center of white view.
I tried using Align & Center widget but its no fitting properly.
How can relative layout works in flutter?
Flutter does not have layout types like android,
But you can place burger image using stack widget.
You can follow this tutorial for reference.
you can not use Relative Layout in Flutter but it Replace using "Stack".
The stack is a widget in Flutter that contains a list of widgets and positions them on top of the other.
stack allows developers to overlap multiple widgets into a single screen and renders them from bottom to top.
Hence, the first widget is the bottommost item, and the last widget is the topmost item.
import 'package:flutter/material.dart';
class StackWidget extends StatefulWidget {
#override
_StackWidgetState createState() => _StackWidgetState();
}
class _StackWidgetState extends State<StackWidget> {
#override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
color: Colors.yellow,
height: 300,
child: Stack(
alignment: Alignment.topLeft,
children: [
Container(
color: Colors.cyan,
width: 200,
height: 200,
),
Container(
color: Colors.red,
width: 150,
height: 150,
),
Container(
color: Colors.blue,
width: 100,
height: 100,
),
],
),
);
}
}
Output:
Done☻♥.

Sizing elements to percentage of screen width/height

Is there a simple (non-LayoutBuilder) way to size an element relative to screen size (width/height)? For example: how do I set the width of a CardView to be 65% of the screen width.
It can't be done inside the build method (obviously) so it would have to be deferred until post build. Is there a preferred place to put logic like this?
This is a supplemental answer showing the implementation of a couple of the solutions mentioned.
FractionallySizedBox
If you have a single widget you can use a FractionallySizedBox widget to specify a percentage of the available space to fill. Here the green Container is set to fill 70% of the available width and 30% of the available height.
Widget myWidget() {
return FractionallySizedBox(
widthFactor: 0.7,
heightFactor: 0.3,
child: Container(
color: Colors.green,
),
);
}
Expanded
The Expanded widget allows a widget to fill the available space, horizontally if it is in a row, or vertically if it is in a column. You can use the flex property with multiple widgets to give them weights. Here the green Container takes 70% of the width and the yellow Container takes 30% of the width.
If you want to do it vertically, then just replace Row with Column.
Widget myWidget() {
return Row(
children: <Widget>[
Expanded(
flex: 7,
child: Container(
color: Colors.green,
),
),
Expanded(
flex: 3,
child: Container(
color: Colors.yellow,
),
),
],
);
}
Supplemental code
Here is the main.dart code for your reference.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("FractionallySizedBox"),
),
body: myWidget(),
),
);
}
}
// replace with example code above
Widget myWidget() {
return ...
}
FractionallySizedBox may also be useful.
You can also read the screen width directly out of MediaQuery.of(context).size and create a sized box based on that
MediaQuery.of(context).size.width * 0.65
if you really want to size as a fraction of the screen regardless of what the layout is.
This might be a little more clear:
double width = MediaQuery.of(context).size.width;
double yourWidth = width * 0.65;
Hope this solved your problem.
There are several possibilities:
1- The first one is the use of the MediaQuery :
Code :
MediaQuery.of(context).size.width //to get the width of screen
MediaQuery.of(context).size.height //to get height of screen
Example of use :
Container(
color: Colors.yellow,
height: MediaQuery.of(context).size.height * 0.65,
width: MediaQuery.of(context).size.width,
)
Output :
2- The use of FractionallySizedBox
Creates a widget that sizes its child to a fraction of the total available space.
Example :
FractionallySizedBox(
widthFactor: 0.65, // between 0 and 1
heightFactor: 1.0,
child:Container(color: Colors.red
,),
)
Output :
3- The use of other widgets such as Expanded , Flexible and AspectRatio and more .
You could build a Column/Row with Flexible or Expanded children that have flex values that add up to the percentages you want.
You may also find the AspectRatio widget useful.
There is many way to do this.
1. Using MediaQuery : Its return fullscreen of your device including appbar,toolbar
Container(
width: MediaQuery.of(context).size.width * 0.50,
height: MediaQuery.of(context).size.height*0.50,
color: Colors.blueAccent[400],
)
2. Using Expanded : You can set width/height in ratio
Container(
height: MediaQuery.of(context).size.height * 0.50,
child: Row(
children: <Widget>[
Expanded(
flex: 70,
child: Container(
color: Colors.lightBlue[400],
),
),
Expanded(
flex: 30,
child: Container(
color: Colors.deepPurple[800],
),
)
],
),
)
3. Others Like Flexible and AspectRatio and FractionallySizedBox
First get the size of screen.
Size size = MediaQuery.of(context).size;
After this you can get width and multiply it with 0.5 to get 50% of screen width.
double width50 = size.width * 0.5;
But problem generally comes in height, by default when we use
double screenHeight = size.height;
The height we get is global height which includes StatusBar + notch + AppBar height. So, in order to get the left height of the device, we need to subtract padding height (StatusBar + notch) and AppBar height from total height. Here is how we do it.
double abovePadding = MediaQuery.of(context).padding.top;
double appBarHeight = appBar.preferredSize.height;
double leftHeight = screenHeight - abovePadding - appBarHeight;
Now we can use following to get 50% of our screen in height.
double height50 = leftHeight * 0.5
MediaQuery.of(context).size.width
you can use MediaQuery with the current context of your widget and get width or height like this
double width = MediaQuery.of(context).size.width
double height = MediaQuery.of(context).size.height
after that, you can multiply it with the percentage you want
Use the LayoutBuilder Widget that will give you constraints that you can use to obtain the height that excludes the AppBar and the padding. Then use a SizedBox and provide the width and height using the constraints from the LayoutBuilder
return LayoutBuilder(builder: (context2, constraints) {
return Column(
children: <Widget>[
SizedBox(
width: constraints.maxWidth,
height: constraints.maxHeight,
...
if you are using GridView you can use something like Ian Hickson's solution.
crossAxisCount: MediaQuery.of(context).size.width <= 400.0 ? 3 : MediaQuery.of(context).size.width >= 1000.0 ? 5 : 4
Code :
MediaQuery.of(context).size.width //to get the width of screen
MediaQuery.of(context).size.height //to get height of screen
You can use the Align widget. The heightFactor and widthFactor parameters are multiplied by the size of the child widget. Here is an example that will make a widget with a fixed height in% ratio
Align(
alignment: Alignment.topCenter,
heightFactor: 0.63,
widthFactor: ,
child: Container(
width: double.infinity,
),
Use scaler to define the layout width and height in percentage
dependencies:
scaler: ^1.1.0+1
After setting this in pubspec.yaml you can use this by following the code -
import 'package:scaler/scaler.dart';
Example After import use this -
import 'package:scaler/scaler.dart';
#override
Widget build(BuildContext context) {
/**
* Container with 25% width of screen
* and 25% height of screen
*/
return Container(
height: Scaler.height(0.25, context),
width: Scaler.width(0.25, context),
child: Container()
);
}
To more detail about this
https://pub.dev/packages/scaler
For width
double width = MediaQuery.of(context).size.width;
double yourWidth = width * 0.75;
For Height
double height = MediaQuery.of(context).size.height;
double yourHeight = height * 0.75;
If you don't want static height and width just use Expanded widget\
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: _title,
home: MyStatelessWidget(),
);
}
}
class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Expanded Row Sample'),
),
body: Center(
child: Row(
children: <Widget>[
Expanded(
flex: 2,
child: Container(
color: Colors.amber,
height: 100,
),
),
Container(
color: Colors.blue,
height: 100,
width: 50,
),
Expanded(
child: Container(
color: Colors.amber,
height: 100,
),
),
],
),
),
);
}
}
I am surprised that no one has yet suggested LayoutBuilder in 2023 which gives you access to the parent's width BoxConstraints.constraints.maxWidth, which is the most versatile method.
Expanded can only set the percentage of the available spacing, but what if you really want to set a percentage based on the actual parent's widget only, not the entire screen width, what if have a fixed width widget in a row, even a more complex, what if you also want an Expanded to expand the remaining Row.
MediaQuery.of(context).size.width is relative to the entire screen, not to the actual parent.
FractionallySizedBox works similarly but you can't put it in Row
Also, this method the perfect emulation of CSS % unit of measurement.
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, BoxConstraints constraints) {
return SizedBox(
width: 470,
child: Row(
children: [
SizedBox(
width: 200,
child: Icon(
Icons.link,
color: Colors.white,
),
),
SizedBox(
width: constraints.maxWidth*0.6,
child: Icon(
Icons.message,
color: Colors.white,
),
),
Expanded(
child: Icon(
Icons.phone,
color: Colors.white,
),
),
SizedBox(
width: constraints.maxWidth*0.3,
child: Icon(
Icons.account_balance,
color: Colors.white,
),
),
],
),
);
}
);
}
}
In this example, we are setting a parent widget of 470 width with Row inside. In the Row, one element has a 200 fixed width, another with a 60% of the parent with 470, another with 30% of that same parent, and another expanding any remaining space.