How to create non-static, custom content in an AppBar - material-ui

I have a material-ui AppBar that sits up high in the composition, something like this:
<App>
<AppBar/>
<Main>
<Route component={FooPage}/>
<Route component={BarPage}/>
</Main
</App>
I would like FooPage and BarPage to be able to "inject" their own content into the AppBar, such as Menus, Selects, etc. -- Without the AppBar or the component that hosts the AppBar to be specifically aware of Foo and/or Bar or any other player that does this. I can imagine a novel way of doing it by having Foo announce to the world that "Foo is active" and having the FooBar-aware AppBar component, respond by saying "Fine...I'll render a Foo-Menu for you.."
What I want is to be able to do is pull this off without the React version of gnarly switch/case. I am pretty newish to React, and I think this is not specifically a material-ui question, but I wonder...Is there is a direct way of loading children into an AppBar (or ToolBar) where AppBar is agnostic towards its contents? And if so, what does that look like syntactically speaking?

AppBar has two properties that can accept elements as values. As such, you could utilize the iconElementLeft or iconElementRight properties to pass in whatever element you want to display.
Check out this JSFiddle as an example:
https://jsfiddle.net/Asalem1/ha6v1714/26/

Related

Flutter Recreating the Hero Transition replacing Navigator with a custom Animator

Looking at the Flutter Hero Transition, it appears to move the tagged Widgets to an Overlay class that exists in all Navigator Widgets but sits above the main content in the stack.
If this is correct, it allows the Hero to widgets to still respond to the Route scope and its animators but exist above the actual route content. How is this actually done efficiently? Surely this involves taking an entire Widget and storing it in a state for the duration of the animation. That Widget still has to respond to intrinsic responses from its original position such as slivers responding to active scroll actions.
Recreating this could be done with state management but I wondered how the standard hero actually does this. It seems like Widgets are effectively duplicated and then conditionally rendered on the screen defaulting to the overlay during the route animation and swapping out the original widget with an Offstage or similar. Is this how it is done?
The reason for trying to understand it is the need to replicate this behaviour in situations where Navigator is not an effective use case for a transition taking place internally on a page. I built an accordion style navigator but still want a hero transition to take place on the AppBar / NavigationBar. I know that this could be done with Navigator but it doesn't suit the use case. I could also predefine the AppBar content for each internal navigator state of the accordion but that is a lot of additional code.

Flutter: Using expansion panel with navigator animate the AppBar when expansion panel is open

In one section of a client's app an expansion panel / accordion is used to open some content. At the same time the AppBar is supposed to animated as is a new route has been pushed but the new route's content should display in the body of the expansion panel.
I have been able to implement this by creating an entirely independent Widget and using a state management library but it is not a tidy solution.
I wondered if it is possible to use the App's main Navigator but not remove the current route's body. This cannot be done with a nested navigator either as the AppBar uses Hero tags that are not reflected between Navigator's.
Is there a simple way to achieve this without using entirely customised state management.
Flutter's in built Navigator, even Navigator 2.0, is well known to not be a particularly friendly interface to use, so I'd recommend the use of a community library that makes things easier.
Auto Route is a popular solution that I use personally and can attest to its quality. For your particular problem it offers navigation observers which you can register. You could use this to trigger the animation of your app bar when the new route is pushed.
It will be a little bit of effort to replace your current navigation with a new library but I'd imagine you'll end up with a cleaner solution at the end instead of customized state management.

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

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.

How to check visibility of a Flutter widget even when covered by another

I'm trying to find a way to check the visibility of a Flutter widget when it's either off screen or when it's obscured by another, for example Drawer, Dialog or BottomSheet.
visibility_detector helps with checking whether it's on the screen or not but does not work with the second use case (known limitation).
Is there a lower lever api that I can use to check whether a widget is actually visible to the user?
My use case: I'm adding a widget to the Overlay when something external happens (similar to Tooltip but not on long press). If the user opens for example the Drawer, the widget will appear on top. I want to detect that the child is not visible and delay or cancel the action.
Do I understand your problem?
You have a widget you want to always be on top?
You want the user to interact with that widget first before doing other things?
Use design patterns to make coding easier, your users will thank you.
You can show a Dialog on-top of other widgets with the showGeneralDialog or showDialog functions. Because Dialogs are a design-pattern used in many apps, users will already know how to use them.
Define app behavior with explicit state.
It is too hard to derive app behavior from rendered UI, not all devices are the same size and shape. This means you should try to write a variable that describes your situation and then write the code you need to make that variable's value correct. It sounds like you want a variable like bool overlayIsShowing.

how to reduce spacing in material-ui?

i am building web app for desktops and i find material-ui wastes lot of space when displaying the components right out of the box.
AppBar is rendered with padding of 24.
Passing the style to the appbar is only adding in addition to 24 instead of overriding.
Just compare the height of menubar of stackoverflow vs material-ui appbar
How to reduce AppBar height atleast 10px less?
You can override component style. You need to apply a className or a style like this :
<AppBar className={classes.appBar} />
With web inspector, you can find your css class. Something like MuiAppBar-XXXXXX
Hope this help!