Is there a way to know the dimensions of a widget before laying it out on the screen? - flutter

I'm trying to implement a breadcrumb widget in my Flutter app and I would like to achieve the following behavior:
Let's say the red outlined area is the space I have for my breadcrumb and that each element of the breadcrumb has a different width. The breadcrumb should be responsive, i.e. it should show elements as long as there is enough space to show them, otherwise, remove some of the elements and add that '...' button in the middle. Clicking on that button shows an overlay that contains the removed elements.
Now, I want to know how much space each breadcrumb element will take before it is laid out on the screen. Only then, I can decide whether there is enough space for it to be shown in the breadcrumb or it should be part of the '...' button.
I tried to use CustomMultiChildLayout which gives you information about how much space a widget takes after laying it out. It also needs to layout each child once, which makes it unuseful in my use case.
P.S: Think about the breadcrumb used in the apple documentation. That's the same behavior I want to achieve.

Short answer, you can't.
You were already using CustomMultiChildLayout, that's good, it shows me that you should have some basic understanding of how flutter rendering pipeline works. Then it should be clear to you of the 3 steps: parent passes down constraints, child reports its size, parent decides where to place the child. So in short, again, you cannot get children's size before layout.
Now move on to the thing you want to achieve. I agree CustomMultiChildLayout cannot achieve what you want to do, but not for the reason you listed. The main problem is CustomMultiChildLayout forces you to layout each child once, and then position them. You must position each child, you cannot skip a child if you don't like it (too big), and you cannot fabricate new stuff that's not your children. If you could achieve these 2 things, then getting children's size after layout isn't going to be a problem.
To achieve those, the easiest way is to use CustomPaint, if everything you need to do, are text-based or just simple shapes. Use TextPainter to layout a text, get its size, then decide whether to paint that text, or paint "..." (skip a child and fabricate your own) instead. You can search on how to do these things easily, but mostly search on TextPainter.
If you want to paint other widgets as your children, and optionally skip some of them while fabricating others, you should write your own RenderObject. That is one level lower than "widgets-level". If you have never done that before, you can research on that topic as well.

Related

How interactive can a component be inside of a widget?

my job is to create a few widgets using widgetkit and swiftui, however the main project is build on uikit so I am not very good with swiftUI. Nevertheless, I would like to know whether I can add a graph inside of, for example, medium sized widget, and can the graph be scrollable to reveal more information? Or could it only be clickable? Thank you.
I know how widgets work, just interested in whether it is possible to create a scrollable graph inside of a medium sized widget.
I'm only just getting started with widgets myself, so happy to be corrected. But interactivity with widgets is very limited - effectively to taps and nothing else. They're designed more to be informational displays than interactive user interfaces.
If your widget is larger than the small size (the square one that takes up the same space as 2x2 app icons on the iPhone home screen), you can have multiple tap targets. For example, if your widget had a list of calendar items, you could set it up so that a user tapping on a specific item opened the app with a view showing that item in more detail.
So no, a scrollable graph isn't feasible. But what you can do is create a graph that shows a snapshot of data that a user is most likely to find useful when glancing at their home screen – and making sure that if they tap on it, they go straight through to a more interactive version of the same data.

How to use SizeTransition with Text inside a Row without overflows

Problem summary
I'm building simple animation in which, simply, a panel expands to the right on a onTap event. The layout can be summarized as follows:
The panel has many tiles. Each tile has its own:
leading icon
title text
trailing icon
Each tile, when expanded, shows the three widgets above
Each tile, when shrinked, just shows the leading icon
The panel is scrollable to hold many icons such as these
At the end of the panel there's a simple icon which, when tapped, triggers the "expand" or "shrink" animation
The animation is built with an AnimatedContainer on the panel and a SizeTransition on the single tiles (via one single controller on the parent class)
The problem is simple: when the tiles shrink, their inner text overflows in the row.
Sample code
I just made this reproducible example on DartPad.
The obvious solution isn't helping me out
The most obvious solution is to simply wrap the Text inside a Flexible Widget: this advised by Flutter's docs and it makes sense, but unluckily it completely breaks my Layout.
Flexible introduces a flex factor that in this context is 100% unwanted.
I want my leading icons to be always at the end of the row, so my Spacer widget should "prevail" there.
I can't just play with flex factors there, as it would unintendedly hide text depending on its value.
Another code smell
Another thing I really don't like is the fact that I have to build a controller on the parent class, but I'm not actually using it on the parent class (I'm just exploiting it so I can give it to the children).
I'm new to animations in Flutter so I'm kinda confused on how I should orchestrate the whole thing here.
Any help will be appreciated / upvoted / accepted. Thank you!
As far as I understood you in a right way you just need set sizes for Row inside of SizeTransition instead of Container sizes
Here is your modified sample https://dartpad.dev/?id=a2408d29a1e8c6ce7a1cef8f21e7491d
I'd try an OverflowBox or a FittedBox (wrapping your text), depending on the result you want to achieve.

Manage Device Sizes MediaQuery Globally

What is the proper way to handle device size globally. The idea is not to have a [MediaQuery.of(context).size.width] on each screen of the app. There is already a question and answer about it, but the only answer is out of date because there was no null safety yet.
The answer suggests creating a constants.dart file, like in the image below:
1
And initialize in the build of the first widget of the application:
2
The problem is that for it to be constant it must have a value, and not wait for the first build. It is also true that the value canchange based on device orientation and I would like to handle this as well.
I have doubts about it. if someone can help me
You cannot save the screen dimensions as a constant, because they will change if the device is rotated, or when the screen is resized, such as for desktop and web apps.
Instead you should be pushing your cutpoint decisions as low as possible, using LayoutBuilder.
LayoutBuilder seems preferable over every use of MediaQuery for sizing a viewport (either the whole screen, or the space left in a column or other layout).
LayoutBuilder also works hard to avoid rebuilding its child if the size doesn't change and the parents haven't had to re-layout.
The builder function is called in the following situations:
The first time the widget is laid out.
When the parent widget passes different layout constraints.
When the parent widget updates this widget.
When the dependencies that the builder function subscribes to change.
The builder function is not called during layout if the parent passes the same constraints repeatedly.
And you don't have to think about "the height of the appbar" ever again, because you're getting the space left, not the total space on the screen.
Check it out: https://api.flutter.dev/flutter/widgets/LayoutBuilder-class.html

Provide different children if Wrap is multi-line vs single-line

I want to display some widgets in a Wrap, and if the widgets are too many to fit on one row, I want to display different widgets (more compact versions of the normal widgets).
How can I achieve this, without resorting to manual measurements of screen width and children? Is there any built-in way to do this with a Wrap or some other widget?
What if with the compact version, the row is still full. Do you want to display the children in multiline then or wrap them with the next line? If it's the latter, then I think it's best to use Wrap from the beginning.
Another practical way is to make the child adaptable as well, by using FittedBox or make it scrollable horizontally by using SingleChildScrollView or ListView.
There can be other scenarios when it's better to show just 4-5 children that's enough to fit a row. Then have a button allowing user to navigate to a detail screen display all the children in a grid or list.

Is there any way to move the search box in Visual Studio Code?

As you can see in the below image, the search box is at the top right corner.
Sometimes this image will cover up the text underneath it. Is there a way to move the search box to some other place? For example, like Atom's or Sublime's search box.
NO, there is currently no way to move it.
There was discussion on this amongst the vscode developers: Find Widget UI enhancement.
We should definitely not make this move both vertically and
horizontally since we do not do this anywhere else in our UX.
Introducing such a new concept does not align well with our general
workbench UX which is not very flexible
Looking at the pictures the docked find widget at the top / bottom
feel too heavy for me.
The current find widget solution I like because it is similar to the
chrome experience which every user on the planet is familiar with
While implementing the docking solution, we found we can actually
split this two issues completely. For the issue of covering search
result, we can allow users to scroll beyond the first line by the
height of Find Widget. It doesn't change Find Widget at all, you can
only scroll beyond first line only when the Find Widget is visible so
it won't cover anything.
I made two changes to the Find Widget for this work item.
You can resize the Find widget horizontally
You can scroll beyond the first line when the find widget is visible.
Which gives us the only customizations we can do to the search/find widget if it (as you said) "covers up text underneath it":
You can adjust the width horizontally
You can set "editor.find.addExtraSpaceOnTop": true to allow "scroll beyond the first line when the Find Widget is visible"