I am not interested in inside workings of logical pixels, I just want to know if flutter automatically use logical pixel
Container(
width:100,
child:...
)
Does flutter uses 100 pixel or logical pixel as width here, I can't figure it out.
You can print screen width
double kScreenWidth(BuildContext ctx) => MediaQuery.of(ctx).size.width;
you can see what it is like
Container(width: 100, ...)
logical pixels
So obvious,
What you see is what you got.
Flutter follows a simple density-based format like iOS. Assets might be 1.0x, 2.0x, 3.0x, or any other multiplier.
Flutter doesn’t have dps but there are logical pixels, which are basically the same as device-independent pixels. The so-called devicePixelRatio expresses the ratio of physical pixels in a single logical pixel.
from flutter dev doc
Related
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.
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.
I am unable to understand the difference between AssetImage and ExactAssetImage. I can use
Image(
image: AssetImage(chocolateImage),
)
Or
Image(
image: ExactAssetImage(chocolateImage),
)
with no performance or memory difference. The only advantage ExactAssetImage has is the scale property, but is that all there to it? If yes, then what's the need of AssetImage?
This is related to the images with different pixel densities you provide in your assets list.
I mean when you have provided images like this:
icons/heart.png
icons/1.5x/heart.png
icons/2.0x/heart.png
If you use AssetImage, flutter will choose between your 3 images depending on the device density pixels.
On a device with a 1.0 device pixel ratio, the image chosen would be
heart.png; on a device with a 1.3 device pixel ratio, the image chosen
would be 1.5x/heart.png.
If you use ExactAssetImage, you select the scale manually, doing somthing like:
Image(image: ExactAssetImage("your-asset",scale: 2)),
AssetImage
AssetImage fetches the image from the AssetBundle then uses the context to determine the exact image to use. Then based on the device pixel ratio and size determines the best configuration for the image this then get passed to resolve
ExactAssetImage
ExactAssetImage fetches images in a similar way while also associating a scale with the image. ExactAssetImage ignores the devices pixels ratio and size in the configuration passed to resolve.
In Conclusion
AssetImage is resolution-aware and can pick the right image based on the right device pixel ratio and size while ExactAssetImage is not. So to more directly answer your question ExactAssetImage gives you more control of memory usage as it will use the exact resolution of the image.
I have images stored as blobs in SQLite. Other tools like DB Browser for SQLite show the images themselves are not upscaled.
I scaled them down from an original image with the following code.
final thumbnailData = encodeJpg(copyResize(
decodeImage(imageData),
width: 400,
interpolation: Interpolation.average
));
When displayed in Flutter they are noticably upscaled.
#override
Widget build(BuildContext context) {
return Image.memory(_getThumbnailData());
}
Image.memory() has a scale argument that defaults to 1.0. Setting it manually to be sure doesn't help either.
I have to set it to some guesstimated value like 2.0 to get the correct scale but I don't understand why and wether 2.0 is actually "unscaled" or still slightly off.
How can I tell Flutter to display the images as they are?
Flutter uses logical pixel instead of physical pixels.
Device pixels are also referred to as physical pixels. Logical pixels are also referred to as device-independent or resolution-independent pixels.
How to convert between physical pixels and logical pixels?
To convert between physical pixels and logical pixels, you can use devicePixelRatio.
The number of device pixels for each logical pixel. This number might not be a power of two. Indeed, it might not even be an integer. For example, the Nexus 6 has a device pixel ratio of 3.5.
MediaQuery.of(context).devicePixelRatio
I am building a flutter application that needs precise measurements of the screen in cm / inches.
According to the docs,
By definition, there are roughly 38 logical pixels per centimeter, or about 96 logical pixels per inch, of the physical display. The value returned by devicePixelRatio is ultimately obtained either from the hardware itself, the device drivers, or a hard-coded value stored in the operating system or firmware, and may be inaccurate, sometimes by a significant margin.
I have tried using these ratios in my application but they are not even close.
Is there a way to accurately calculate the dimensions of the screen?
Flutter's pixel coordinates are given in logical pixels rather than physical pixels. However, MediaQuery will give you the conversion ratio.
var mediaQuery = MediaQuery.of(context);
var physicalPixelWidth = mediaQuery.size.width * mediaQuery.devicePixelRatio;
var physicalPixelHeight = mediaQuery.size.height * mediaQuery.devicePixelRatio;
(Note that this code can only be run in a place where a BuildContext object is available, such as a build method or a StatefulWidget's companion State class.)