Closed jassmith closed 5 years ago
Let's get this conversation humming, because we really need to hear from you, our community of developers!
FIRST, thanks @jassmith for laboring to capture this and craft a proposal for us to discuss in the open here.
I'm going to share some of my thoughts, ask some stupid questions, and ask some hopefully-not-too-leading questions. As the Program Manager for Xamarin.Forms I often have to ask questions in such a way that it makes it sounds like I don't have a clue (sometimes I don't), but really I just need to hear things from YOU without putting words in your mouth.
There are things I like in this proposal, because I can see how they might address some the problems I've been talking to many, many of you about, and we are working towards solving.
I also have reservations.
I'll kick off here with a couple general threads of thought about the Shell concept and the developer experience.
to get a complete app experience that is properly structured, uses the right elements, with very little effort and a clear path to being good by default.
If I use this approach to describe my application at the top level, I get:
Is that accurate? Other benefits I should highlight?
Instead of App
I have MaterialShell
. I need to learn/adopt a new top level application paradigm to benefit from this?
Once I'm into my app, I'm back in ContentPage
land, correct? But all my Button
s and Entry
s are material-fied and pretty. Can I still OnPlatform
and the like to diverge the look (or behavior) to be different on another platform?
What's my migration path look like from an existing app to using this "shell"? I introduce the new MaterialShell
, describe how I want my app to be structure and look, and just run it to see the new goodness?
What are my options if I like the way the Flyout
or the menu items look, but I need to tweak them to match my designers comps? At what point am I saying "Ugh, I should've rolled this all myself" and moving what I have to a standard Xamarin.Forms app structure?
If I have to totally abandon the MaterialShell
, do I lose all that styling goodness and I'm back where I started (like today) with an Entry
looking quite different between iOS and Android and UWP? I would like to not.
There's a tipping point I'm anticipating. After I've used this approach to get going quickly, I will hit some limitation and need to explore my options. What are they and at what point am I better off not usingMaterialShell
?
I'll close this first comment with a few questions to everyone reading.
If possible, screenshots / design images would make even better.
Also check out this:
@jassmith It would have been great if the whole idea is presented as images. Kudos to the effort of putting the specifications up. My questions might be not correct.
My queries are
Will this also include something akin to the TextInputLayout to support floating labels/placeholders as well as error messages? If yes, then I think Binding
should be extended to include 'ValidateOnDataErrors` similar to wpf.
See my implementation of this here https://github.com/XamFormsExtended/Xfx.Controls/blob/develop/src/Xfx.Controls/XfxBinding.cs
Also, I wonder if MaterialShell should extend Shell so that one could create a HumanInterfaceShell for the iOS look and feel.
@ChaseFlorell that was going to be my comment as well. Material is great, but it's another thing if we want to write our own shells to suit particular UI needs.
@davidortinau , @jassmith ,
Thanks for putting together this spec and allowing us to provide feedback.
Is the problem that this proposal attempts to address well defined?
Yes. The navigation system is not completely developed in Xamarin Forms so there is an open ended issue of how to complete it, or circumvent it altogether.
Is it a problem you share?
Yes.
As you read this spec, what problems that you have faced on previous projects do you feel this would solve for you?
I'm going answer with this question by saying that I don't think it will solve problems. Our particular problems are that the current navigation system is too rigid, not that it is not rigid enough. The clearest example for us is the TabbedPage. There is no TabbedView view, so if we want tabs in our app, we must use TabbedPage. So, the whole screen must be taken up by the TabbedPage and we cannot use real estate for own buttons, or other controls that we might want to put on the screen. My recommendation would have been to move more functionality out of Pages and down to Views rather than moving functionality in Pages up to yet again higher layer.
Things like FloatingMenu, and FlyoutBehavior scare me because they imply that navigation will be further hard coded in to the Xamarin.Forms system and further control will be taken away from the software developers. I can see some value in having a more standardized approach, but it will definitely come at a cost.
We have always worked in other XAML based technologies like Silverlight, WPF, and UWP. In those technologies, we have a much more open ended approach where we are able to define more of how the navigation works. Recently, we engaged a UI/UX consultant. He was unaware of XF's quirks. We just asked him to build us some screens based on the functionality of our software. Large swathes of what he recommended could not be implemented because of things like not having a TabbedView. I fear that instead of making navigation easier, what will happen is that this framework will actually make it harder to implement the designs that are given to us by UX/UI designers.
The other thing I would say is that this framework looks unprecedented in other XAML platforms, and I would say that the priority should be on providing standardization across the platforms rather than providing new frameworks that the other platforms won't be compatible with. We're currently building for three platforms now: Silverlight, Xamarin.Forms, and WPF. What we need is standardization across those platforms to create less deviation, not more.
@dylanberry ,
it's another thing if we want to write our own shells to suit particular UI needs.
Yes. This is my concern. Each app has its own particular use cases, and more rigidity is likely to make it harder - not easier to implement these.
There is also this concern: https://github.com/xamarin/Xamarin.Forms/issues/2452#issuecomment-380991817
I'll echo the above, as well as ask how gestures and pointers will function irt shape primitives?
A general comment is that for every line of code added to a system, there is 3+ chances of buggy code being added. There are already a lot of bugs in Xamarin Forms that need fixing. More code means the chances of bugs being added increase exponentially. There will be more bugs. I feel that the XF team should be working to reduce the size of the code base rather than increasing it. Decreasing the code base is the only way to decrease the likelihood that bugs will occur.
Why inventing a new thing again instead of fixing existing bugs and first make sure everything is rock solid?
For me, it's been touched on but navigation is the single biggest stumbling block in Xamarin Forms and has caused me the most heartache over the last three years.
The navigation is not consistent across all three platforms with MasterDetail pattern causing many issues with the hamburger forcing you to push pages modal, you then have to implement a custom navigation bar as you can't add back but the animation looks awful on Android (even in MD).
Ideally you should be able to opt-out and override the content of the navigation bar with your own ContentView in many cases. PlatformSpecifics was originally mooted as something which would have allowed positioning of toolbaritems (way back when I was speaking to Bryan) but it transpired to be something of limited use.
Ability to override framework stuff like page popped animations
A lot of what's proposed seems very very useful, As long as you can just use material shell in specific pages and it isn't app wide it code be really useful. It's certainly something we'd use because at current I keep saying "It's a limitation of Xamarin Forms" to our UX guy a lot (as I did in my previous role). Dare I say it, we should get the feedback from a UX perspective who have previously styled Forms apps. It's should be opt-in like XamlC.
Not sure about the name though, FlexShell would make more sense...but we now have Flexbox (even though we never asked for it...sorry David, couldn't help myself 😄)
Also, would this mean themes are kind of dead? never used them anyway.
@mackayn
It's certainly something we'd use because at current I keep saying "It's a limitation of Xamarin Forms" to our UX guy a lot (as I did in my previous role).
OK, but, wouldn't make more sense to fix or improve the current implementation instead of creating a completely new one, which will come with bugs and limitations too? It says right there that:
MaterialShell is an opinionated API at points"
Seriously, in how many different directions can Xamarin Forms go? The XF team is barely able to keep up fixing current XF implementation for at least Android and iOS, and now this? What about bug fixing, fixing XAML preview, what about performance?
There is\was a ticket opened by someone with a proposal to add simple but much useful support for cross platform solid and gradient brush, but @jassmith response was that it would be problematic. But now this ticket proposes the same thing.... How's that not problematic anymore? Go figure
@opcodewriter
Yes, I've been saying that for the last year, there's navigation weirdness that holds back the Prism team for example and they've never been able to get issues closed.
I'm just trying to offer constructive feedback for now though, Xamarin Forms is at a critical juncture in it's evolution, this API could address many of the pain-points if it's implemented in a flexible way and not an app wide approach.
@jassmith does this mean that XF will take the Flutter approach (using a rendering engine instead of native controls) for the Shell?
Folks, yesterday Jason and myself had a discussion on how to improve this spec and we will be doing a large update, we are splitting this into different issues.
I'd like to echo some of the above sentiments: please let's just improve on what we have, unless of course you have limitless resources, then go for it 😉
There are so many things still left out: fixing ListView (hard to believe this is still doesn't work properly), implement controls like CheckBox, RadioButton, implement brush support (SolidColorBrush, GradientBrush), ability to display a Popup based on a Page or ContentView, fixing bugs (see recent bug reported about transparent views), performance, tooling, and so much more....
Why would you want to start a new thing?????
@TonyHenrique Yeah pictures would be great. I unfortunately am not an artist and do not own the rights to the images I am using for my own reference. I am hoping some design team member will have time to help me produce proper images for the spec.
@muhaym
@ChaseFlorell no, but Im open to suggestions if you want to attach an amendment to the spec. As for the Shell vs MaterialShell thing, I addressed that above. Step 1 was making sure MaterialShell made sense then breaking it out to a base class is step 2.
@dylanberry the base class wont really make that much easier. Its not as simple as changing DrawingTemplates. I intend to implement the MaterialShell aspect of this in platform specific code for optimal performance.
@RichiCoder1 gestures will be coming in here but the gist is the views with subregion gestures are coming as part of the CommandableSpan API and it will be expanded to support drawings with gestures as well. However in general it would be advised NOT to use gestures and let the native backends handle input. This is unrelated to the MaterialShell spec at this point now and belongs on the Drawing spec where I am happy to go into more detail. The long and short is the reason DrawingTemplate is a thing is we may include a SliderDrawingTemplate which has multiple Drawings that the renderer knows how to compose a slider out of and allows the input handling to continue to be handled in the native backend. This does not mean you would be forced to do this, it would simply be an optional thing to make the renderer fast as possible.
@mackayn a Transitions/Segue API is coming and should land in here soon. I am still working out some of my initial proposal naming. It will certainly be something that comes in phases with only Page Transistions being in phase 1. That will let you override framework animations however. As for opt-in. The Shell must be the root of your application and cannot nest anything but TemplatedPage's. That said the internal control theming is 100% in your control. Its little more than a magic switch to turn on/off the new templates and you can control that switch the same way we will. This lets you opt in and out of the theming at the page, the layout, or even the control level.
@encrypt0r not exactly. Think of it as a hybrid. It will allow for rendering but under teh hood its all platform specific controls just being themed with drawing code. However there is an escape hatch to Skia that could be easily added (though I doubt it makes it anywhere near a v1).
@opcodewriter ListView2 (obviously it wont actually be named that) is on the roadmap this year at long last. Why a new ListView? Well the original API leads to a nearly limitless number of bugs and issues that we can't really effectively fix without totally breaking backwards compatibility. Things like Cell/ViewCell and ItemsView
Unfortunately I cannot think of any way to resolve this within the ListView type itself, and I don't think the community has been able to either unfortunately. The best option right now is to keep ListView as it is, and then make something far sleeker with less overhead, less bookkeeping, less odd types that don't need to exist and trust the target frameworks to do what they do best.
Simply removing the old recycling strategy, which would be a huge backcompat breaking change we can't do, would remove a sizeable portion of the Xamarin.Forms codebase. ListView2 will bring you much closer to the metal by removing these items which were intended to be guard rails (or in the case of Cell, the unholy merger of 2 different internal projects) and are now just hurting everyone.
The old caching strategy impacts EVERY renderer in existence today. Its the reason why every renderer supports having its Element changed. If that went away by my best estimate about 10% of all code in the project goes away. It's really the biggest cancer of the project.
@davidortinau you get your own comment just because yours has so much lovely formatting!
If I use this approach to describe my application at the top level, I get:
- an app themed to look the same on every platform
- material design (in this case) patterns on by default
- the latest navigation patterns enabled with configuration
- I don't have to labor to customize Entry or Button to look the same on iOS and Android and UWP?
Is that accurate? Other benefits I should highlight?
Yes that is correct. There are lots of other benefits you can highlight but they should become obvious once you start messing with it. Like you can do bottom sheets, have a FAB, navigate using URLs (update still coming) and much much more.
Instead of App I have MaterialShell. I need to learn/adopt a new top level application paradigm to benefit from this?
Wrong. Your apps MainPage is the MaterialShell. Application is still your app root.
Once I'm into my app, I'm back in ContentPage land, correct? But all my Buttons and Entrys are material-fied and pretty.
With the exception to where you were wrong above, yes this is correct.
Can I still OnPlatform and the like to diverge the look (or behavior) to be different on another platform?
Yes.
What's my migration path look like from an existing app to using this "shell"?
Look at the Google Play Store repro case, imagine putting all your apps current pages in there. This only replaces those areas in your app where you are directly using Nav/Tab/MD pages. It doesn't have any impact on your ContentPages.
I introduce the new MaterialShell, describe how I want my app to be structure and look, and just run it to see the new goodness?
Bingo
What are my options if I like the way the Flyout or the menu items look, but I need to tweak them to match my designers comps?
You fully control the header, how the header collapses and hides. You fully control the look/feel of each of the "Cells" (they wont be cells) in the flyout. You fully control the header for each group in there as well. In effect you control the "look" of everything, however we still need to add a couple additional places for you to place extra content.
At what point am I saying "Ugh, I should've rolled this all myself" and moving what I have to a standard Xamarin.Forms app structure?
If the Google Play Store physical layout flyout looks completely different from what you want. Not marginally different, completely different.
If I have to totally abandon the MaterialShell, do I lose all that styling goodness and I'm back where I started (like today) with an Entry looking quite different between iOS and Android and UWP? I would like to not.
No MaterialShell is just setting some default resources so its children get them. You will be able to do that yourself. You might have to do it anyway, we haven't actually committed to making MaterialShell do that by default. If we do make it opt-in instead of opt-out, it will be a single API call for any subtree.
There's a tipping point I'm anticipating. After I've used this approach to get going quickly, I will hit some limitation and need to explore my options. What are they and at what point am I better off not using MaterialShell?
The intention is you are NEVER better off going non-Shell. You might not want Material but you should always want Shell (again the Shell base class is coming). Why? The look/feel of shell will be much more configurable, the navigation story will be much more unified, there should be nothing sane you can do with the other pages that you can't do with Shell.
Better, the intention is to make sure the Shell renderers are actually easily configured and sane. No magic hidden classes, not custom native view subclasses that we take hard deps on. As much as is possible every component of the renderers will be composed and swappable. That way if it doesn't work how you want it to, you can actually fix it...
Why didn't we do that at first? It wasn't a design goal in the early days and then we just ended up married to that... This is big enough and new enough that we dont have to carry that mistake with us.
@opcodewriter
Seriously, in how many different directions can Xamarin Forms go? The XF team is barely able to keep up fixing current XF implementation for at least Android and iOS, and now this?
What about bug fixing, fixing XAML preview, what about performance?
^^ This
@migueldeicaza
Folks, yesterday Jason and myself had a discussion on how to improve this spec and we will be doing a large update, we are splitting this into different issues.
Miguel, this is clearly going to be a big job. I can't speak on behalf of all developers, but I can tell you that my team wants three things: stability, performance and flexibility. We want bugs fixed. We want our app to run smoothly, and we want to be able to implement the designs that our UI/UX designers give us without turning around and saying "Sorry, that's just not possible in our platform". This spec seems to run counter to that goal. This is going to require more resources being thrown at the job which means that your resources are not freed up to work on stability, performance and flexibility.
Would this be the new default behavior/way to develop in xamarin forms? Or would we still have an option to build our apps with each platform specific look and feel?
@DanielCauser while I suspect in the long run this may become the "default" way, this will in no way replace the current way. It will simply be a more integrated and modern way which will provide a lot more of the shell people are currently building by hand by default. On top of that since we will be providing the shell as a single control we can optimize a lot about how its drawn and laid out. No longer will you have 3 drawing passes just for your shell.
I'm cautiously in favour of this idea, provided that the improvements it proposes are worked out by means of improvements in the underlying Xamarin Forms code. If this adds more complexity on top of Forms I would not use it. For my money though I would much prefer to have developer resources directed towards making Forms more flexible, faster and finished than it is currently. If that happened, I could make all the proposed new features here for myself. DIY in this case is almost certain to fit me and my clients better than a generic toolkit provided by Xamarin, however good it might be. With a couple of notable exceptions this proposal doesn't solve problems I'm facing at the moment.
@jassmith
Why do you want to start working on this whole new feature now? Doesn't make more sense to focus on the above first?
About your comment above related to ListView: I applaud any kind of bold take on it, including completely redesign\replace it. It's not like everything is so great in Xamarin Forms things should not be touched\changed.
@opcodewriter
1) Yup there are. I agree its a problem and will continue to be the priority work item that I personally push for.
2) Performance on Android is part of the driving reason for this. This gives the framework more heads up time for page transitions so we can hide things like JIT time. We can proactively load and retain pages far more intelligently. What the X.F. team can't fix is overall JIT time. If you run your app in Android with AOT enabled and its much faster, there is nothing I can do to help you.
3) No arguments here.
Why do you want to start working on this whole new feature now? Doesn't make more sense to focus on the above first?
This work isn't scheduled, we are just discussing a spec here. My management will schedule it when they feel its appropriate with my advise.
About your comment above related to ListView: I applaud any kind of bold take on it, including completely redesign\replace it. It's not like everything is so great in Xamarin Forms things should not be touched\changed.
ListView truly is the bug bear of Xamarin.Forms. Of those 500 issues, 220 of which are marked as bugs (there are lots of housekeeping or enhancement issues too), north of 25% are just to do with ListView. For comparison thats about the same percentage that have to do with the entire UWP platform. Worse a fair number of the crashers in Android that are basically described as renderer gets used after dispose are also ListView bugs however they are unlikely to show up in my search since ListView will show up nowhere in the search query.
@jassmith beside fixing existing issues (beside ListView, there are other things which still don't always work right), there are also important features which were left out (random order):
I wish more work was done in the direction of making the framework truly richer, and not add stuff like CSS style or Flexbox (which came with their own issues).
@opcodewriter
True popup support (basic and common feature still missing)
Fair, it never seems to get prioritized high enough to become real. This actually got pretty far along at one point.
Cancel page navigation when navigating back (long outstanding issue)
This is actually something MaterialShell is intended to address. There are pretty solid reasons this can't be done in NavigationPage.
Basic controls missing(no CheckBox, RadioButton, and more)
Some of these are part of the F100 initiative going on now.
Cross platform drawing (Canvas control or some other way)
That would be the sister API to this as speced in #2452
Support for cross platform drawing of solid\gradient brushes (SolidColorBrush, GradientBrush)
Same answer as above.
@jassmith
Fair, it never seems to get prioritized high enough to become real. This actually got pretty far along at one point.
OK, looking forward for prioritizing it by end of 2018 :)
This is actually something MaterialShell is intended to address. There are pretty solid reasons this can't be done in NavigationPage.
Could you please give more detail why this can't be done in current implementation?
Some of these are part of the F100 initiative going on now.
I see. Fingers crossed..
Could you please give more detail why this can't be done in current implementation?
I wont go into this more here because we are getting massively off track but the gist is as follows:
There are some other minor concerns in there too regarding how it impacts styling. Thats the long story short however. If you still wish to discuss this particular feature I suggest opening a new issue :)
@jassmith
I thought just handling gestureRecognizerShouldBegin
and call something like OnBackButtonPressed
should be enough.
Overall I really like a lot of what I am reading, however this does not feel like something that should be done in the core Xamarin Forms nuget/repo.
This is an opinionated approach that should be built on top of Xamarin Forms, not built into it. I see this as a separate library that enables developers to take a different approach. The required parts of Xamarin Forms that need to be exposed should be, and this should be built on top of those bits.
Just like when developers make the decision to go with Xamarin Classic/Native or Xamarin Forms, I can see a similar decision to go with Xamarin Forms or Xamarin Forms with a Shell.
Xamarin Forms should focus on creating the best cross platform UI framework without trying to conform platforms to look like one another. Today Xamarin Forms does a great job of making sure platform feel is respected.
I could see a base Shell being in the Xamarin Forms repo and some code around handling Shells, but Material Shell seems too tightly coupled to a specific design language and navigation pattern for me to think it should be in the Xamarin Forms repo.
@MisterJimson Thank you for your feedback. The exact placement of the public API surface area is not yet decided. There are pros and cons of both approaches.
The spec will be updated (hopefully very shortly) to have both a Shell and a MaterialShell class. The MaterialShell class would be the part we consider moving out of core. Shell would be what you have described.
Updated with Shell breakout and navigation spec update
I would really like it if existing XF implementation is made...stronger and better to enable something like this to exist as an addon, not as part of BCL. So having strong underlying platform that is correct and stable will benefit existing apps and any new layers like this one.
Looking forward to the evolution of this thing.
@jassmith @brianlagunas
Just a few observations.
I just want to ensure existing pain points and limitations are addressed as well as new having new capabilities.
Sounds great.
I'm very new to XF but the framework does have a bit of a reputation for being somewhat fragile, though certainly this is improving rapidly thanks to your efforts.
So for what it's worth, this is my opinion :-)
It's great that Xamarin getting a lot of love at the moment but I agree with @opcodewriter, both the tooling and the framework could do with some technical debt paying back.
I also like the thoughts from @MisterJimson that this should be a different layer - but you must be honest with yourselves about your capacity and how many frameworks you can support. We're all prone to coding exciting new shiny things, and avoiding the difficult decisions, but we rely on you to develop a solid foundation for our code.
I have enough problems getting my code working without worrying about someone else's :-)
XF is in a good place at the moment, it has the potential to become a really solid toolset.
Thanks for all your hard work on this, it does show.
@mackayn
BackButtonBehavior, surely there should be a visibility property in case you don't want it at all?
Set the command with CanExecute returning false. I opted to not add a secondary method for the moment.
The materialshell navigation scheme is like Prism, will it work with these existing frameworks? (Prism, FreshMVVM, MVVMCross)
I sure hope so! I can't be sure but I was thinking of them and all their troubles. Thats why all navigation happens through a single event for example.
Can you override completely the layout in the navigation bar? as it stands Forms is extremely limited in this regard and you end up with clunky looking navigation bars forcing you down the customrenderer route, safe in the knowledge that a new version of Forms will most likely break your custom code.
This part is harder. I would like to allow as much extensibility here as possible but I am really open to suggestions on how to improve this in a sane and reasonable manner.
MasterDetail isn't touched on much, will you be able to customise the flyout menu?
You can set the header to any arbitrary view, you control the template used for group headers and items, and you can add menu items. You control some aspects of the layout but not 100%. Again it would be good to get some thoughts on what else you think you need. I clearly see a need for a footer with a footer behavior property.
What control will we have over the hamburger?
BackButtonBehavior also overrides the hamburger. Perhaps it should be renamed. Again I am open to suggestions here. Originally I called it LeftBarButton, but in RTL situations its not on the left...
@stevehurcombe technical payback is continuing and ongoing. This will be run in parallel by a far smaller contingent of the team. Unfortunately the reality is a lot of this spec is about technical payback in a weird way. Xamarin.Forms incurred a huge amount of API debt with its 1.0 release, and has been carrying that debt ever since. Certain things in X.F. are very difficult to make work right, or even impossible to make work right, simply due to the way the API expresses them.
Tight interactions between tabbar and navbar is one such area, making sure navigating between tabs or items in the MDP is glitch free is another area. There are lots of areas where little hiccups will occur because each element is not able to take a holistic view of the shell of your app.
As for the tooling, there is an entirely separate team dedicated to this and they are making huge strides. The internal tooling has improved massively in the past 6 months and I really look forward to you getting to try that out!
@mackayn
The materialshell navigation scheme is like Prism, will it work with these existing frameworks? (Prism, FreshMVVM, MVVMCross)
Fear not, @jassmith brought this to my attention before the community realized the issue was here... so I can say with some confidence, it's an issue he certainly cares about as much as we do. You can be sure that it will be something that we look to support. Something of this magnitude will certainly require a lot of cross team dialogs to ensure that it meets the needs of the Forms developer at large, as well as meeting the needs of MVVM frameworks like Prism.
@dansiegel
Good to know both teams are in dialog, that'll all I needed to know 👍
@jassmith It's obvious by now the way some of things are running or were architectured in XF is not the best. So instead of putting lipstick on the pig (not wanting to be rude here), why not either recreate a new framework from scratch or massively refactor the existing one. I know, it sounds very scary, but I'm pretty sure the large majority of Xamarin Forms developers would not mind, all of us would be excited to refactor our apps or whatever just so we have apps which run much better. I've seen PR rejected with good refactoring because "we do not want this kind of changes". I am not sure who made that rule, but he should take a deep breath, relax and maybe reconsider the "rule". What is the best: Keep having frustrated devs using a framework which can't keep it up or having frustrated devs which need to do some refactoring work? Just my 2 cents...
@opcodewriter you and I agree but this is offtopic for this spec.
Just read the new material around navigation and I really like it. Love having a sort hand for binding navigation commands, and orienting navigation around URLs (like and I assume influenced by Prism) is smart.
Ironically the URI navigation scheme was something we wanted to do way back in the day and started push Prism to implement because we couldn't reasonably get it into the framework. Not to take any of their credit, they deserve 100% of that :)
The exact semantics of the shorthand are still up for grabs.
I think it will likely end up more like:
<Button Command="{segue:Uri}" CommandParameter="app://Foo/Bar/Baz" />
or
<Button Command="{segue:Push}" CommandParameter="{DataTemplate local:MyPage}" />
So the extensions can be more precise about what parameters they take. The namespace is used mostly to keep things easy to discover with intellisense.
@jassmith I really like that this segue stuff. Can I ask how you intend to support push modal?
I don't have all the details, but I could envision url nav just like prism, wrapped up in markup extensions.
<!-- push -->
<Button Command="{segue:Uri}" CommandParameter="path/to/page" />
<!-- push modal -->
<Button Command="{segue:Uri Modal='true'}" CommandParameter="path/to/page" />
<!-- reset stack -->
<Button Command="{segue:Uri}" CommandParameter="app://root/path/to/page" />
First thing to note is that URI navigation will only work with Shell. It's the only place we can consistently make sense of the stack without having weird edge cases and we can design the navigation interactions to support the concept.
For now we are only supporting full URIs. Partials are a lot harder to deal with because they are contextual.
Your 3 examples then would be, assuming the current location is: app://Shell/Apps/Games/Details
In particular this means you are in an Shell, whose current ShellItem has the Apps Route, whose current ShellTabItem has the Games route, who has a ContentPage pushed onto its stack which has the Route Details.
<!-- push -->
<Button Command="{segue:Uri}" CommandParameter="app://Shell/Apps/Games/Details/page" />
<!-- push modal -->
<Button Command="{segue:Uri}" CommandParameter="app://page" />
<!-- reset stack -->
<Button Command="{segue:Uri}" CommandParameter="app://Shell/Apps/Games" />
In a shell uri the first location is always a Shell. If it is not it is assumed to be a modal push. Next is the ShellTab, then the ShellTabItem. After that follows the navigation stack of the ShellTabItem. I have no intention of backporting URI nav to all possible page controls at the moment. This gets REALLY hairy with people who use MasterDetailPage's...
With Route registration and Route properties there is no need for type based routing. I am going to remove it form the spec.
@jassmith giving more thought to this navigation stuff, and I have some questions
CanExecute
NavigationParameters
whereby we can pass not only basic values via the querystring /Navigation/MyPage/MyPageDetails?id=33
, but also complex objects new NavigationParameters {{nameof(MyObject), MyObject}}
. Do you plan to support something similar?@ChaseFlorell
1) With segues? You can't currently. Definitely needs to be thought about more. There is a way to make a segue command but it... sucks. That would let you handle it but at that point its REALLY not worth it.
2) A Segue will disable itself until the push is completed. Further attempts to activate the command no-op until the previous navigation task completes.
3) You can use a traditional navigation like push/pop with segues. These are relative actions.
4) [QueryParameterAttribute] may or may not already exist, I can neither confirm nor deny. ;)
It is unlikely we will add complex objects support. The idea is you use converters to take your simple values and turn them into complex objects.
Xamarin.Forms Shell Spec
Make it simple and straightforward for new developers to get a complete app experience that is properly structured, uses the right elements, with very little effort and a clear path to being good by default.
Shell is an opinionated API at points, it does not always default every value to some .Default which may change based on the running platform. Instead it may set a value which is then respected across all platforms regardless what the platform default is.
Note: Drawing Spec moved to: #2452
Visual Treatment
Needs screenshots...
Shell Hierarchy
Understanding the Shell hierarchy at first can seem overwhelming at first. It represents a complex hierarchy and provides powerful mechanisms for minimizing the amount of boilerplate xaml required to create rich hierarchies.
Thus when first learning shell it is easiest to learn without the shortcuts first, and then introduce the shortcuts to see how to easily minimize the amount of XAML being written.
Note that all samples that follow do not use templated ShellContent's, which are discussed elsewhere in the spec. Failure to properly use ShellContents with a ContentTemplate will result in all pages being loaded at startup, which will negatively impact startup performance. These samples are for learning purposes only.
Fortunately using ShellContents with ContentTemplates is usually more concise than not using them.
No shortcuts
Many of these samples will look needlessly complex, and in reality they are. In the next section these will get simplified.
A simple one page app
The top bar can be hidden entirely by setting
Shell.NavBarVisible="false"
on the MainPage. The Flyout would also look rather sparse in this mode and is thus disabled in this sample.Two page app with bottom tabs
By adding a section
ShellSection
to theShellItem
another bottom tab appears. Settings the approriate title and icon allows control over the Tab item title and icon.Two page app with top and bottom tabs
By adding a second
ShellContent
to theShellSection
a top tab bar is added and the pages can be flipped between when the bottom tab is selected.Two page app using flyout navigation
The flyout is re-enabled in this sample. Here the user can switch between the two pages using the flyout as an intermediary. A header has also been added to look nice.
Using shorthand syntax
Now that all levels of the hierarchy have been shown and breifly explained, it is possible to leave most of the unneeded wrapping out when defining a hierarchy.
Shell
only ever containsShellItem
s which only ever containShellSection
s which in turn only ever containShellContent
s. However there are implicit conversion operators in place to allow for automatic up-wrapping.A simple one page app
With implicit wrapping the Page is automatically wrapped all the way up to a
ShellItem
. It is not needed to write out all the intermiedate layers. TheTitle
andIcon
from thePage
will be bound up to any implicitly generated parents.Two page app with bottom tabs
The pages are now implicitly wrapped up into ShellContent and their own ShellSections. This results in two different tabs being created, just like before.
Two page app with top and bottom tabs
Two page app using flyout navigation
Here the implicit wrapping goes all the way up to shell item so there is no need for us to do any wrapping ourselves.
Navigation Model
Push Navigation
All navigation is based on the View’s .Navigation property. Pushes go into the current ShellSection that is displayed. This means in a push event the top tabs will go away and the bottom tabs will remain.
URI Navigation
The Shell can be navigated using the standard Navigation property as discussed above, however shell introduces a far more convenient navigation mechanism.
Navigation URI's are formatted as follows:
All items in the shell hierarchy have a route associated with them. If the route is not set by the developer, the route is generated at runtime. Runtime generated routes are not gauranteed to be stable across different runs of the app and thus are not useful for deep linking.
Handling the Back Button
Since Shell will be in the enviable position of not having to use native controls, all forms of back button overriding can and should be supported.
Proper handling of the back button needs to support the following features:
The API needs to be granular to the page level for ease of use, but also be able to be handled further up the stack in a more general level.
Code Samples and API
Samples
Single Page App using Shell
Single Group of Tabs app (no Flyout)
Multiple pages in flyout with no tabs
Single Page Searchable App
API Definition
Shell
This is the base class for Shell's. It defines a somewhat strict navigational model however all shells must adhere to it in general. It does not include any theming or design language specific features.
Description
Attached Properties:
ShellItem
s,ShellContent
s, orPage
s to override the default behavior.Page
to define if the NavBar should be visible when it is presentedPage
will cause itsPadding
to be set such that its content will not flow under any Shell chrome.Page
to define if the TabBar should be visible when it is presentedPage
to define theTitleView
Properties:
FlyoutBehavior
for theShell
.FlyoutHeaderTemplate
is not null, this is passed as theBindingContext
to the inflated object. IfFlyoutHeaderTemplate
is null andFlyoutHeader
is of typeView
it will be used directly. Otherwise it will be shown by calling ToString() and displaying the result.FlyoutHeader
when the Flyout needs to be scrolled to show contents.DataTemplate
used to show a Group Header if aShellItem
requests to be displayed as a Group of Tabs in the Flyout. If null, no header is displayed.DataTemplate
used to show items from theItems
collection in the Flyout. Allows the developer to control visuals in the Flyout.MenuItem
s which will show up in the flyout in their own section.DataTemplate
to use when displayed aMenuItem
in the Flyout.Public Methods:
ShellNavigationState
. Returns a Task which will complete once the animation has completed.Public Events:
Shell
is about to perform a Navigation either due to user interaction or the developer calling an API. The developer may cancel Navigation here if possible.Shell
has completed a Navigation event.ShellItemCollection
A collection for
ShellItem
sMenuItemCollection
A collection for
MenuItem
sShellSectionCollection
A collection for
ShellSection
sShellContentCollection
A collection for
ShellContent
sShellNavigatingEventArgs
An
EventArgs
used to describe a navigation event which is about to occur. TheShellNavigationEventArgs
may also be used to cancel the navigation event if the developer desires.Properties:
Shell
. CallingGoToAsync
with thisShellNavigationState
will effectively undo this navigation event.Shell
will be in after this navigation event completes.Public Methods:
ShellNavigatedEventArgs
Properties:
Shell
.Shell
is in when this navigation event completed.ShellNavigationState
Properties:
Shell
Constructors:
ShellNavigationState
with a null LocationShellNavigationState
with the Location set to the suppliedstring
ShellNavigationState
with the Location set to the suppliedUri
ShellNavigationSource
BaseShellItem
Properties:
BaseShellItem
is currently checked in the Flyout (and thus should be highlighted)BaseShellItem
is selectable in the chromeShellGroupItem
Properties:
ShellItem
Properties:
ShellSection
.ShellSectionCollection
which is the primary content of a ShellItem. This collection defines all the tabs within a ShellItem.ShellSection
Properties:
ShellContent
of the ShellSection.ShellContentCollection
which is the root content of the ShellSection.Methods:
INavigation
interfacesInsertPageBefore
method is calledINavigation
interfacesPopAsync
method is calledINavigation
interfacesPopToRootAsync
method is calledINavigation
interfacesPushAsync
method is calledINavigation
interfacesRemovePage
method is calledShellContent
Properties:
ContentPage
or theBindingContext
of thePage
inflated by theContentTemplate
ShellContent
. TheContent
property will be set as theBindingContext
after inflation.SearchHandler
Properties:
ClearPlaceholderCommand
ClearIcon
location when the search box is empty.Command
ICommand
to execute when a query is confirmedItemsSource
.Shell
s chrome.Protected Methods:
Query
is changed.SearchBoxVisiblity
BackButtonBehavior
Command
FlyoutDisplayOptions
Determines how the
ShellGroupItem
should display in the FlyoutMenu.ShellGroupItem
will be visible as a single entry in the Flyout.ShellGroupItem
will be visible as a group of items, one for each child in the Flyout.FlyoutHeaderBehavior
Controls the behavior of the FlyoutHeader when scrolling.
FlyoutBehavior
DataTemplateExtension
This extension quickly converts a type into a ControlTemplate. This is useful for instances where the template would otherwise be specified as
This can then be condensed down to
Odds and Ends
What happens when you select a tab in Flyout which has been pushed to?
This is the equivalent of focusing the tab and calling PopToRoot on it.
What happens when I switch ShellItems and there are items on the backstack of a ShellContent of the old ShellItem
If the old ShellItem is templated, the back stack is lost. If the ShellItem is not templated the BackStack stays intact and when switching back to the old ShellItem the backstack will be properly reflected. Switching back may clear the backstack however as indicated in the above answer.
Effecient loading of pages
A major problem with using the Shell is the ease by which a user can end up loading all pages at the start of their application run. This large frontloaded allocation can result in quite poor startup performance if a large number of content pages are needed. In order to fix this templating should be employed when possible.
Templated ShellContents
Templating shell tab items is the most granular form of templating available, it is fortunately also the easiest to do. Take the following shell.
When this Shell loads, all 9 pages will be inflated at once. This is because no templating is employed. To employ basic templating we can convert this into:
Pages are now only loaded as needed and can be unloaded as needed as well. If needed the ShellItem's themselves can also be templated with a collection and a DataTemplateSelector which prevents even the ShellContents from having to be loaded eagerly, however this is largely unneeded and templating ShellItem is more useful for Shells that have ShellItems with large numbers of otherwise similar tabs. Templating the ShellContent should be the key area to provide templating for performance concerns.
Reconstructing the Google Play Store User Interface
Please note this is not intended to be a demo of the best way to code an application, but really the most concise format to shove together the UI for GPS. It also makes no attempt to virtualize the relevant pages by using ViewModels and DataTemplateSelector's. This means this would be quite bad performing as all pages would be loaded at app start. Reader is warned.
All page content is assumed to be working right, this is only to get the general idea of the chrome.
Shell.xaml
A proper implementation of this would use ShellItems for every page and set the ItemsSource and ItemTemplate. This would allow each page to only be loaded once it is needed and unloaded when no longer needed.
The store pages
And to add the search bar.
And so on and so on setting the colors and the content correctly.
For pages like the Settings page where the flyout should not be accessible until the back button is pressed:
TODO
Issues
ISearchHandler [FIXED]
There is a lot this interface is doing and worse it's probably going to need to be expanded as time goes on. Therefor it stands to reason that it should probably instead be an abstract base class the user can implement. This unfortunate means yet another object allocation. However it maintains flexibility in the future. It is likely this change will happen.
Floating Menu
The attachment API is a bit heavy and perhaps too confusing for users. Worse it might not map very well to all platforms to make sure the attachment works with animations. More work is required to validate this API.