Why is the flutter MediaQuery starting from top of the screen - flutter

When I am using the MediaQuery to resize a container, like this =>
height: MediaQuery.of(context).size.height - 100,
the subtraction or the resizing of the container starts from the bottom instead of from the top. Please someone should help me out

You could wrap it with Align. It happens because naturally Flutter draw the Widgets from Top Left.
Something like this:
Align(
alignment: Alignment.bottomCenter,
child: Container(
height: MediaQuery.of(context).size.height - 100,
color: Colors.white,
),
),

As an addition to the answer by #FederickJonathan,
Align gives you some default positions to align your widget as described here: https://api.flutter.dev/flutter/painting/Alignment-class.html#constants
But you can also customize the position.
However you like, by giving Alignment as Alignment(X, Y).
X = -1.0 - 1.0, starting from left->right
Y = -1.0 - 1.0, starting from top->bottom
Fun fact:
Not Just flutter but almost all Rendering framework which paints the screen to display your views always starts from the Top-Left corner of the screen.
It is known as the origin point of the view/screen.
In flutter, if no co-ordinates or alignment is provided, then you'll see that the view is plotted starting from the top left corner.
The Origin point is also considered as the source of Light in material design. So all the shadows are cast to the bottom to the right side initially.
Update: Material Design combines various light sources for shadow. So the above fact is not true for material design but still you can see it in some other design guide lines.

Related

Position a widget, inside a stack, but according to the center of the widget

I want to position a widget, CustomWidget, but at the specified position, i.e, top, left values, in the Positioned widget, I want there to be the center of my CustomWidget, instead of the top-left corner of my CustomWidget.
I want something like this:-
Stack(
children: [
Positioned(
left: x,
top: y,
alignment: Alignment.center, //Alignment of the child widget, such that at (x, y) there is the center of the widget.
child: CustomWidget(),
),
],
);
Here is the type of UI I am trying to make, I am trying to make both cases:-
CustomWidget does not have any specific type, I am currently trying to make a general method, It might be a simple Text Widget with some variable value, or maybe a Widget with a Row of Image, Divider and Text.
I am basically using CustomWidget as a kind of popup, which will be used in case of some extra information, and also as a stamp over a widget, wherever the user clicks, in both cases, I cannot be certain of the size.
Note:- I do want to position the CustomWidget at a specified offset in the stack, but want that there should be the center of the CustomWidget instead of the top-left corner of CustomWidget.
You don't need to use the Positioned widget. Try using the Align widget, remember to add alignment: Alignment.center, to center it.
I have developed a package, with many helpful components (basically the components, which I use often, in all my projects, so to prevent writing the same thing everywhere 😜). So there I have added this new Widget named PositionedAlign this work according to the above question. I hope this helps anyone who might need it.

Positioning widgets on top of Network Image based on X and Y coordinates

I want to position custom widgets on top of an image based on X and Y coordinates. Think of it as an overlay. Until now, I have tried a solution, where I used a Stack in a combination with Positioned, to position widgets above the image. The problem arises when I try this solution on different screen sizes. The overlaid widgets are off, depending on the screen size I'm testing on.
Here's my current implementation:
Expanded(
child: InteractiveViewer(
constrained: false,
minScale: 0.1,
maxScale: 2.0,
child: Stack(
children: [
Image.network(widget.plan.image),
Positioned(
bottom: 2927,
left: 6700,
child: SvgPicture.asset("assets/svg/pin.svg", height: 200)
)
],
)
),
)
Note that I'm also wrapping everything in InteractiveViewer because the Image I'm getting from the backend is very large.
EDIT: I have noted that for some reason the image dimensions are different on different displays. For example, photo dimensions on iPhone X are 10224x6526, where on iPhone 13 Pro Max image dimensions are 8192x5228. I am now investigating further why this is happening as this is probably the reason why custom widgets drawn on top are shifted on different screens.
EDIT 2: After a long research I've finally came across something. I own two physical devices - iPhone 12 and iPhone X. I was testing on simulator and something really odd happened; simulator is logging different image dimension simulating the same physical device - let me explain:
Original Image dimension coming from backend:
10224 × 6526
iPhone 12 simulator image dimension log after network call:
8192x5228
iPhone 12 PHYSICAL device image dimension log after network call:
10224 × 6526
iPhone X PHYSICAL device image dimension log after network call:
10224 × 6526
Which effectively means that something is working differently regarding the image scaling when using iOS simulator and physical device.
The best way to do this will be to try to position your items relative to the screen's width and height in percentage.
bottom: MediaQuery.of(context).size.height * 0.5 // 50% of the screen's height
left: MediaQuery.of(context).size.width * 0.3 // 30% of the screen's width
You are free to change the percentiles to suit you.
EDIT 2
x = (6700/width-of-photo) * 100
y = (2927/height-of-photo) * 100
With the issue concerning the size of the image, you might want to consider placing it inside a widget and giving it a max-height and max-width values.

Should I use absolute pixel values in my Flutter widgets, or should I scale them to the screen?

I am coming to Flutter from a web background, where I am used to defining screen elements in terms of percentages of the height and width of the screen, or of elements that contain them.
I just completed a course.
Now that I am enthused and want to start building an app, I am a little confused, as the course only spoke of heights & widths in absolute pixel values. I can see this being problematic with different aspect rations, and especially with different orientations.
Is there a canonical approach to this? The official docs also seem to use absolute pixel values, so maybe I am missing a fundamental point.
A search suggests that I might use MediaQuery and then scale everything according to that. But, I don't see widespread use of that in code samples.
Is there a non-opinionated standard approach?
I am a little confused, as the course only spoke of heights & widths in absolute pixel values.
Actually, flutter uses density independent pixels (dp) for width/height arguments. dp actually scale with resolution, meaning 1 dp is displayed as the same PHYSICAL distance on every device. You don't have to worry about your elements being displayed at different sizes, just because the resolution of the screen they're on changes.
To be precise, flutter calls them logical pixel and:
By definition, there are roughly 38 logical pixels per centimeter, or about 96 logical pixels per inch, of the physical display.
So think about them as you would think about cm.
I am used to defining screen elements in terms of percentages of the height and width of the screen
Nonetheless, you might want to layout your widgets in a relative fashion (relative to the screen or the parent). For that purpose, flutter has different solutions:
Flexible
Expanded
Wrap
MediaQuery
LayoutBuilder
GridView
other layout options
Is there a non-opinionated standard approach?
It is a very opinionated question to begin with, but for example, Material design is a common standard for mobile-design. Flutters layout widgets are based around this approach.
But in the end, it is your design choice. For example, to achieve a responsive layout grid you could use Wrap, or you could use LayoutBuilder and determine yourself how you would like to layout rows and columns.
I would recommend you to scale widgets based on the size of the screen. This allows your application to be more flexible and adjust to various platforms and sizes such as large tablets or small phones. In order to do this, I recommend you to use the widget FractionallySizedBox which allows you to size widgets using a percentage of the screen size. For example, if you want a button widget to fill up 50 percent of a screen's width you can use the following code:
Container(
alignment: Alignment.center,
child: FractionallySizedBox(
widthFactor: 0.5,
child: FlatButton(
onTap: () {},
child: Text("PRESS HERE")
)
)
)
This code creates a button positioned in the center of the screen with a width of 50 percent of the screen size's width. You can also change the height of the button with the heightFactor field. By using this code the button widget will scale up and scale down for different screen sizes while still maintaining a size of half of the screen's width. For more resources, you should check out this video by the Flutter Team: https://youtu.be/PEsY654EGZ0 and their website on the FractionallySizedBox here: https://api.flutter.dev/flutter/widgets/FractionallySizedBox-class.html.
The FractionallySizedBox however is only one of many different approaches to making your flutter app fit to different screen sizes. Another approach is to use the AspectRatio Widget. Below is an example of this:
Container(
alignment: Alignment.center,
child: AspectRatio(
aspectRatio: 3/2
child: FlatButton(
onTap: () {},
child: Text("PRESS ME")
)
)
)
This code will create a button with a 3 to 2 ratio between its width and height. If the screen size changes the button will increase or decrease in size accordingly while again maintaining the 3 to 2 ratio. If you want more information the Flutter team also has a video on it (https://youtu.be/XcnP3_mO_Ms) along with some documentation here:(https://api.flutter.dev/flutter/widgets/AspectRatio-class.html).
Both widgets are perfectly fine and are considered standard practice to use but I personally use FractionallySizedBox more.
I hope my answer was helpful.

Flutter Text widget proportions

Is there any way to change size proportions for letters (words/texts) in Flutter?
Ideally, I need to have the ability to change the size of some Container, for example, and the Text child of this Container has to fill all the space from edge to edge, no matter what size proportions this container has. If the container has size 10*200 and the child of this Container is Text with "3", so three number has to be very thin/tall looking number. I hope it makes sense.
Pictures below are showing what I mean, approximately (don't look at the red background):
The first picture has, let's say, the proportion of 20*160 and the seconds on has the opposite (160*20).
Maybe there are some packages for that?
Just for people who might have the same questions, the transform widget will be something like that:
Transform(
transform: Matrix4.identity()
..setEntry(0, 0, xProportion),
..setEntry(1, 1, yProportion),
alignment: FractionalOffset.center,
child: Text("3"),
)

What does actutally Bottom overflowed by 123 pixels mean in flutter

I am learning flutter and currently switched from android to flutter.In flutter i mostly get an error something like
bottom overflowed by 234 pixels or renderbox overflowed by 340 pixels.And i fixes that problem by increase the height of the widget.If so then how to know that what much size giving to widget.I mean in android we can declare the height of the layout to be wrap content and its works perfectly.Please explain me that how can i avoid this situation because if i fixes the issue by changing the height of widget in one device then in devices of other screen sizes if throws same error ?Here is a image which throws an error.Ignore the red error , see the error in below screen.Thanks in advance.
!https://imgur.com/a/PsZzeMp
If you want to give fixed width and height to your widgets wrap it with SizedBox.
You can specify fixed width and height and you child widget will be the exact dimension.
If you want one of the dimension fixed and the other as big as the parent widget, you can try something like this:
SizedBox(
width: double.inifinity,
height: 50.0
child: Conttainer()
)
If you are worried about giving fixed dimensions. You can give the height or width according to the ratio of the screen size. You can get the height and width of the screen like this:
double width = MediaQuery.of(context).size.width;
Use the above value to give the width to your widgets like below:
Container(
width: MediaQuery.of(context).size.width * 0.8,
height: 100,
)
To answer question in the comment. You can do the following to wrap the text with dynamic content.
ConstrainedBox(
constraints: BoxConstraints(
maxWidth: 100
),
child: Text(
'ADASFASF ssss'
),
)
The above code will wrap the text to next line if the text widget is more than 100 pixels wide. As we don't have any constraints on the height.
Overflow happens when the minimum size of a child widget is bigger than the parent's constraints (width and/or height).
Which means you can:
make the parent widget bigger (eg: SizedBox(height:, width:,))
make the child smaller (eg: using a FittedBox(fit: BoxFit.scaleDown) widget)
Though the first method will not allow you a size bigger than the parent's parent widget. It should be enough to build the children relatively to their parents and not the other way.
In your case, it seems like you text + image widget is taking a little too much space. I recommend wrapping it in a FittedBox that will scale down the child widget until it fits in you bottom bar.
FittedBox(
fit: BoxFit.scaleDown,
child: _buildChildWidget(),
)
You can then wrap it in other widgets to build the layout you want (Row, Expanded, Flexible, LayoutBuilder, ...).
As the overflow issue usually happens because text or images are too big. A good exercise is trying to make your app work while setting text size to the maximum value allowed by the accessibility options of your device. You can do the same with images by setting an image size relative to your text size for example.
Paddings and margins can also cause problems because they leave less space for the child widget.