Flutter: Creating the ruler in millimetre - flutter

I am creating a ruler app where I can measure anything in millimetre.
Something similar to this app https://play.google.com/store/apps/details?id=org.nixgame.ruler&hl=en_IN but very basic.
I am repeating the Divider widget into a Column widget and keeping a gap of 6.299 as given.
class Ruler extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: rulerPin(350),
),
);
}
List<Divider> rulerPin(int count) {
return List.generate(count, (i) {
return Divider(
height: 6.299,
thickness: 1,
);
}).toList();
}
}
But the problem is when I measure with the physical ruler on my mobile phone the values do not match. Check the given screenshots.
I am using this reference Calculate logical pixels from millimeters
Kindly suggest if I am following the correct approach.

You have to find out the pixel frequency of the device. Then with MediaQuery you have to add the pins at equal intervals calculated. There may always be shifts in calculations with fixed numbers.
If it does not happen again, it definitely means that there are errors in the parts that give information.(Like pixel frequency information).
I will research for you and edit this answer.
Result: You can calculate in 3 stage;
1) Get DPI (dots per inc)
double dpi = _getDpi();
android : getting the screen density programmatically in android? with method channel
iOS : You can create a dpi list of apple device models.(device list) They are not too much. And then you can get device model with device_info
2 ) Calculate pixel size
Flutter work with logical pixels.
So we need known how many logical and how many physical pixels
dart
Size logicalSize = MediaQuery.of(context).size;
///How many physical pixel for 1 logical pixel
double pixelRatio = MediaQuery.of(context).devicePixelRatio;
///How many logical pixel for 1 mm.
double pixelCountInMm = dpi / pixelRatio / 25.4;
//e.g output = 7.874015748031496
3 ) Calculate
///I am not sure thickness include height
/// if yes you can set divider height : pixelCountInMm - tickness
List<Divider> rulerPin(int count) {
return List.generate(count, (i) {
return Divider(
height: pixelCountInMm,
thickness: 1,
);
}).toList();
}

Related

can the top, bottom etc of Positioned widget in a stack be specified as percentage?

When using the Positioned widget in flutter, can I specify the top and bottom parameter as a percentage of the stack instead of exact pixels?
I have an Idea! I don't know, how do you like it.
You can't use percentages directly for exact pixels.
but you can use MediaQuery to use percentages.
final size = MediaQuery.of(context).size; //this var has 100% of your screen
now you can use a percentage of your screenSize in the top, bottom, right, and left properties.
like
top: size.height / 2, //it will be divide your screenHeight by 2 means 50%
I have 2 suggestions :
first :
in the Stack Widget, there is an alignment property, where you can choose a value from the Alignment enum to align the Positioned widget
you can also wrap Positioned widget with Align widget
if this doesn't fit in your case
in that alignment property you can use Alignment constructor to specify a y and x values to align your widget, so in example :
alignment: Alignment(0, 0)
will center your widget
alignment: Alignment(-1, -1)
will align your widget to the left top
alignment: Alignment(1, 1)
will align your widget to the right bottom
with this, you can use those between those values to get into a specific alignment
with multiplying by your calculated percentage to get into specific align based on %

How to create a dynamic page in flutter

I'd like to list some components in a row and when a component reaches the end of the page it should just move to the next row. In this way I expect the page to be adjusted dynamically to the size of the screen. I don’t have a code example because it’s a theoretical question.
You can use the screen width/height to calculate the size of the row widgets.
To get the screen size do the following:
final height = MediaQuery.of(context).size.height;
final width = MediaQuery.of(context).size.width;
final height = MediaQuery.of(context).size.height; final width = MediaQuery.of(context).size.width;
// or you can use screen util package it make your screen responsive
and make your code inside SizedBox
it will work
like this :
SizedBox( height: 100, width: width * 0.85 // this mean width is 85% of screen width// child: //your code ),
The obvious answer is Wrap. Give it some children, and it lays them out by default start to end horizontally, and when the next child doesn't fit, it starts a second line.
You don't even need to put it in a row, but you can certainly use it as part of a row or part of a column.

How to make the application display correctly on various screens?

The application looks good on a Pixel 4 XL (resolution of 1440 x 3040) but is overflowing on a Samsung A5 (720 x 1280).
I expected the components to be scaled based on the resolution/ppi, but it seems that I misunderstood.
So how can I fix this ?
Any help is greatly appreciated.
Thanks.
One way of achieving a great looking UI on different screen sizes is to size your widgets relatively to the screen size, and not with pixel amounts, since when the screen's width or height is smaller or bigger, and the widgets are the same size, the UI will either go out of bounds or you will have empty spaces in your UI.
how to achieve that:
in your build function you can store the screen size in a variable:
Widget build(BuildContext context) {
final screenSize = MediaQuery.of(context).size;
...
then in your widgets that you are returning in the build function, for example a container, change the pixel values to values relative to the screen size:
instead of
return Container(width: 50, height: 70);
write stuff like:
return Container(width: screenSize.width * 0.1,
height: screenSize.height * 0.12);

What is delta, globalPosition, localPosition and primaryDelta in Flutter?

I am struggling to understand the properties delta, globalPosition, localPosition and primaryDelta of DragUpdateDetails. I read the documentation for DragUpdateDetails but it didn't really help much.
I found some question asked: What is primaryDelta and delta in DragUpdateDetails and What is the difference between globalposition and localposition in flutter?. First one has no answer whereas second one only has explanation for globalPosition and localPosition.
This is a sample code for dragging a container:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
double _xPosition = 0;
double _yPosition = 0;
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: SafeArea(
child: Container(
child: Stack(
children: [
Positioned(
top: _yPosition,
left: _xPosition,
child: GestureDetector(
onPanUpdate: (DragUpdateDetails e) {
setState(() {
_xPosition += e.delta.dx;
_yPosition += e.delta.dy;
});
},
child: Container(
height: 200,
width: 200,
color: Colors.black,
),
),
)
],
),
),
),
),
);
}
}
In this example why are we using delta but not globalPosition or localPosition. I mean of course dragging will not work as expected but how to know when to use delta or globalPosition or localPosition?
Can someone provide me a quick explanation for these properties? It would really mean a lot. Thanks!
According to the Source code of DragUpdateDetailsclass:
delta → Offset
The amount the pointer has moved in the coordinate space of the event receiver since the previous update
Meaning, The distance covered by dragging since the last pointer contact. Delta gives dx for horizontal distance and dy for vertical distance.
primaryDelta → double
The amount the pointer has moved along the primary axis in the coordinate space of the event receiver since the previous update
primaryDelta gives the absolute distance in only one primary direction of dragging, meaning if the drag is primarily in horizontal axis(GestureDragUpdateCallback + Horizontal only) then this value represents the drag distance in the horizontal axis. If the drag in is vertical axis (GestureDragUpdateCallback + Vertical only) then this value represents the drag amount in the vertical axis.
Note: if the GestureDragUpdateCallback is for a two-dimensional drag (e.g., a pan), then this value is null.
globalPosition → Offset
The pointer's global position when it triggered this update.
The position of the pointer on the screen with reference to the whole screen area and origin point at the top-left corner of the screen. Global Position gives x for horizontal co-ordinate and y for vertical co-ordinate
localPosition → Offset
The local position in the coordinate system of the event receiver at which the pointer contacted the screen.
The position of the pointer just like the global position, except the referential frame being the widget/render object instead of the whole screen. Here, The widget is the one that has received the pointer contact.
Explanation with respect to the example code
According to the example code that is provided, I can safely say that when you are dealing with the positioning of any draggable widget you must have an initial position.
For the initial position, globalPosition or localPosition can be used. Which one to use is specific to the widget tree and use of the app.
Once the initial position is set, you can use delta or primaryDelta to find the new position for the draggable widget to move to when dragged by following formula:
newXPosition = initialXPosition + (dx or primaryDelta in horizontal axis)
newYPosition = initialYPosition + (dy or primaryDelta in vertical axis)
One thing to keep in mind while using delta and primaryDelta is that, if the widget can/should recognize the drag events in both axis, only delta will be provided, primaryDelat will be null.
Otherwise, if only one direction drag is expected then using only primaryDelta will work as expected, at this point delta will have only one value as a non-zero value and other as 0 based on which direction the drag is to be recognized.
Let me know if you have any other questions about this in the comments.

Flutter - How to proportionally center a view (centered with multiplier offset)

I'm wondering if in Flutter there are any good ways of imitating the iOS Xcode constraint where you center a view inside another (say, vertically), and supply a multiplier such that instead of being exactly centered (50% of the way down the parent view), it's positioned at 30% down, or 70% down, or whatever.
(Rather than use a fixed margin from the top of the screen, I'd like to "float" a header view down by 20% of the screen height...)
FractionallySizedBox is enough by itself to handle such layout
FractionallySizedBox(
heightFactor: .5,
widthFactor: 1.0,
alignment: Alignment.topCenter,
child: child,
)
This will top center a widget taking helf the height of its parent and full width
All my FractionallySizedBox efforts have been unreliable, but here's a way that's proven far stabler for me - using LayoutBuilder and SizedBox as a spacer:
LayoutBuilder(builder: (context, constraints) => Column(
children: <Widget>[
SizedBox(height: (constraints.maxHeight - constraints.minHeight) * 0.2,),
myWidget
],
))
This way constraints give me the ability to calculate 20% of the parent height, and apply that as a spacing using a simple SizedBox.
Set in container of parent view
Container(alignment: Alignment.center, ...)
I found one way, but I'm not sure it's the neatest yet:
For vertical proportional centering:
Embed your layout inside a Center widget that is itself inside a FractionallySizedBox. Provided that FractionallySizedBox is at the top of the screen, by changing its heightFactor you effectively change the centering position caused by the Center widget.
new FractionallySizedBox(
heightFactor: someHeightFactor,
child: Center(
child: myChildWidget
),
);
i.e. if parentHeight = the height of the parent widget to this FractionallySizedBox, and parentY = the (absolute) y origin of that parent widget, then setting heightFactor = 0.6 would center your UI child inside a region measuring 0.6 * parentHeight, therefore with an absolute y center = parentY + 0.3 * parentHeight.
Horizontal proportional centering would be the same but using widthFactor on the FractionallySizedBox.
Use FractionallySizedBox to size a widget relative to all available space, and wrap it with a Container or Align to specify the alignment of it.
For example:
Container(
alignment: Alignment(0, -0.5),
child: FractionallySizedBox(
heightFactor: 0.5,
widthFactor: 0.8,
child: Container(color: Colors.blue),
),
)
This makes a blue box that's 50% of screen height and 80% of screen width, positioned at 25% down vertically.
Note, for the Alignment class, it takes in 2 parameters, for x and y axis alignment, ranges from -1 to +1. For example, (0,0) is center, (-1, -1) is top left corner, so here (0, -0.5) centers it horizontally and lifts it up half way vertically, resulting in 25% padding from the top.