I want to develop a mobile application and the first page should be a Login page. When de user has been logged, I want to show a FlyoutPage with differents options, but my problem is when I use NavigationPage to change from the login page to the FlyoutPage the system hides the FlyoutPage menu options and shows the back button.
This is the login page.
.
You can use AppShell. Try this:
AppShell.xaml
<Shell x:Class="mycompany.AppShell"
xmlns:pages="clr-namespace:mycompany.Pages"
xmlns:mycompany="clr-namespace:mycompany"
x:DataType="mycompany:AppShell"
FlyoutBehavior="Flyout">
<FlyoutItem Title="HOME">
<Tab Title="tab1">
<ShellContent ContentTemplate="{DataTemplate pages:AboutPage}"/>
</Tab>
<Tab Title="tab2">
<ShellContent ContentTemplate="{DataTemplate pages:HomePage}"/>
</Tab>
</FlyoutItem>
<FlyoutItem Title="item1">
<ShellContent ContentTemplate="{DataTemplate pages:ItemPage}"/>
</FlyoutItem>
<FlyoutItem Title="ABOUT">
<ShellContent ContentTemplate="{DataTemplate pages:AboutPage}"/>
</FlyoutItem>
</Shell>
At AppShell.xaml.cs
public AppShell()
{
InitializeComponent();
//goto login if you want
Navigation.PushAsync(new LoginPage());
}
At LoginPage.xaml.cs
public StartPage()
{
InitializeComponent();
//hide bottom tabs
Shell.SetTabBarIsVisible(this, false);
}
At LoginPage.xaml hide the top navigation:
<ContentPage Shell.NavBarIsVisible="false">
</ContentPage>
The final step is to navigate back to the Shell tab page, the best place would be at the ViewModel of your LoginPage, you have to complete the login process and go to your main screen.
Task.Run(async () =>
{
//go to our main shell page with tabs and flyout menu
await Shell.Current.Navigation.PopToRootAsync();
});
Hope that helps.
Related
I have several page in MAUI Shell XAML:
<ShellContent
Title="Dashboard"
ContentTemplate="{DataTemplate local:MainPage}"
Route="MainPage">
<ShellContent.Icon>
<FontImageSource Glyph="" FontFamily="AwesomeSolid" Color="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource Gray100}}" />
</ShellContent.Icon>
</ShellContent>
<ShellContent
Title="Ot"
ContentTemplate="{DataTemplate local:OtherPage}"
Route="OtherPage">
<ShellContent.Icon>
<FontImageSource Glyph="" FontFamily="AwesomeSolid" Color="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource Gray100}}" />
</ShellContent.Icon>
</ShellContent>
Shell navigation works fine, but if user taps "back" on OtherPage the application will not return the user back to the main page. Also, navigation from Shell Flyout does not add a back button to the OtherPage.
If I put a button on OtherPage and try to explore navigation stack it seems like it doesn't record previous page:
private async void Button_Clicked(object sender, EventArgs e)
{
Console.WriteLine(Shell.Current.Navigation.NavigationStack.Count); // prints 1
await Shell.Current.Navigation.PopAsync(); // doesn't work
await Shell.Current.GoToAsync(".."); // doesn't work
await Shell.Current.GoToAsync("///MainPage"); // navigates to MainPage
}
From the last call I can see that navigation is working, but navigating from Shell doesn't add page to the navigation stack.
How do I achieve the behavior that:
Application starts on MainPage
User navigates to OtherPage via Shell Flyout
User taps "back" button while on OtherPage and returns to MainPage
The shell content in the Shell.Xaml will be default set as the root page in the navigation stack. In other words, when you navigates to a page via Shell Flyout, that page will be a rootpage.
And the back button will show only when you go to a page which is not added into the Shell as a flyoutitem. So both of the OtherPage and the MainPage will not show the back button when you navigation between the two pages. You navigate between the two pages with the Shell.Current.GoToAsync is same as using the Shell Flyout.
So you can remove one of the ShellContent and only use the Shell.Current.GoToAsync to navigate between the two page or only use the Shell Flyout.
Update
In the OtherPage's xaml.cs:
protected override bool OnBackButtonPressed()
{
await Shell.Current.GoToAsync("///MainPage");
return true;
}
I have an App that's in development for quite a while now and I wanted to "port" it to iOS. When I start it, the splash screen appears and it works fine. After that splash screen it turns into a black screen, but it doesn't crash. If I create a New Application and try to run it it works perfectly. I don't use any storyboards and I'm trying to deploy to a iPhone SE. It currently has iOS 15.3 on it. What could cause this?
EDIT:
Here is the Code of the first page that the App opens:
<?xml version="1.0" encoding="UTF-8"?>
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Easy_Learn.Pages.Shellpage"
xmlns:pages="clr-namespace:Easy_Learn.Pages"
xmlns:local="clr-namespace:Easy_Learn"
xmlns:viewtemplates="clr-namespace:Easy_Learn.ViewTemplates"
xmlns:windows="clr-namespace:Xamarin.Forms.PlatformConfiguration.WindowsSpecific;assembly=Xamarin.Forms.Core"
windows:Application.ImageDirectory="Assets"
FlyoutHeaderTemplate="{DataTemplate viewtemplates:FlyoutHeader}"
Shell.TabBarIsVisible="False"
Shell.TabBarForegroundColor="{StaticResource backGroundColor}"
Shell.BackgroundColor="{StaticResource backGroundColor}"
Shell.TitleColor="{StaticResource textColor}"
Shell.ForegroundColor="{StaticResource textColor}">
<ShellContent ContentTemplate="{DataTemplate local:MainPage}" Title="Lernen" Icon="LightBulb.png"/>
<FlyoutItem FlyoutDisplayOptions="AsMultipleItems">
<ShellContent ContentTemplate="{DataTemplate pages:AllVocabs}" Title="Alle Vokabeln" Icon="Book.png"/>
<ShellContent ContentTemplate="{DataTemplate pages:deklkonj}" Title="Deklinationen" Icon="table.png"/>
<ShellContent ContentTemplate="{DataTemplate pages:Konjugationen}" Title="Konjugationen" Icon="table.png"/>
<ShellContent ContentTemplate="{DataTemplate pages:adjectives}" Title="Adjektive" Icon="table.png"/>
<ShellContent ContentTemplate="{DataTemplate pages:profile}" Title="Profil" Icon="account.png"/>
</FlyoutItem>
</Shell>
I have an App that's in development for quite a while now and I wanted to "port" it to iOS.
Do you want to port your app to Xamarin.Forms or Xamarin.iOS?
The code in FinishedLaunching is totally different with the two ways .
If Xamarin.Forms
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
LoadApplication(new App());
return base.FinishedLaunching(app, options);
}
If Xamarin.iOS
//AppDelegate (< iOS13)
[Export ("application:didFinishLaunchingWithOptions:")]
public bool FinishedLaunching (UIApplication application, NSDictionary launchOptions)
{
Window = new UIWindow (UIScreen.MainScreen.Bounds);
Window.RootViewController = new UIViewController();
Window.MakeKeyAndVisible (); // important
return true;
}
//SceneDelegate (>= iOS13)
[Export ("scene:willConnectToSession:options:")]
public void WillConnect (UIScene scene, UISceneSession session, UISceneConnectionOptions connectionOptions)
{
Window = new UIWindow(scene as UIWindowScene);
Window.RootViewController = new UIViewController();
Window.MakeKeyAndVisible (); //important
}
Using this I found that there were a few lines in the info.plist file that cause this issue. You just need to remove these lines from your info.plist and it works fine.
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<true/>
</dict>
I am new to xamarin forms and shell and I am currently trying to design the hierarchial structure of an app using Shell (Xamarin.Forms Shell). I want to design my app so that once the user logs in, he will be taken to a page (let's call it home page one) that can be chosen from the flyout menu and has it's own unique tabs at the bottom. I also want there to be another page visible in the flyout menu (let's call it home page two) so that if the user clicks on home page two, it is taken to home page two, which has it's own different tabs at the bottom. The user should see different tabs depending on which home page they chose in the flyout menu.
Here's the idea of the overall layout:
Once user starts up application, they are taken to a start page (StartPage)
The start page gives the user the choice to login (LoginPage) or register (RegistrationPage)
Once the user successfully logs in, they are taken to home page one(HomePageOne) which contains 4 tabs at the bottom
If the user opens the flyout menu, it should display an item for HomePageOne and HomePageTwo, as well as a logout menu item.
If the user clicks on home page two (HomePageTwo), they are taken to home page two, which has different tabs from home page one and vice versa
If the user chooses to logout, they are taken back to the start page (StartPage)
I currently have two questions. First, I'm not sure how to define my shell to account for the different home pages having different tabs. Second, when the user chooses to logout, it is still displaying the flyout menu (hamburger menu) even though that should only be visible while the user is successfully logged in.
Here is my AppShell.xaml:
<ShellItem Route="Start" FlyoutItemIsVisible="False">
<ShellContent Route="StartPage" ContentTemplate="{DataTemplate local:StartPage}" />
</ShellItem>
<ShellItem Route="Login" FlyoutItemIsVisible="False" >
<ShellContent Route="LoginPage" ContentTemplate="{DataTemplate local:LoginPage}" />
</ShellItem>
<ShellItem Route="Registration" FlyoutItemIsVisible="False" >
<ShellContent Route="RegistrationPage" ContentTemplate="{DataTemplate local:RegistrationPage}" />
</ShellItem>
<FlyoutItem Title="Home Page One" Icon="icon_about.png">
<ShellContent Route="HomePageOne" ContentTemplate="{DataTemplate local:HomePageOne}" />
</FlyoutItem>
<FlyoutItem Title="Home Page Two" Icon="icon_feed.png">
<ShellContent Route="HomePageTwo" ContentTemplate="{DataTemplate local:HomePageTwo}" />
</FlyoutItem>
<!-- When the Flyout is visible this will be a menu item you can tie a click behavior to -->
<MenuItem Text="Logout" StyleClass="MenuItemLayoutStyle" Clicked="MenuLogout_Clicked">
</MenuItem>
Here is my AppShell.xaml.cs:
public partial class AppShell : Xamarin.Forms.Shell
{
public AppShell()
{
InitializeComponent();
Routing.RegisterRoute(nameof(StartPage), typeof(StartPage));
Routing.RegisterRoute(nameof(RegistrationPage), typeof(RegistrationPage));
Routing.RegisterRoute(nameof(LoginPage), typeof(LoginPage));
}
private async void MenuLogout_Clicked(object sender, EventArgs e)
{
await Shell.Current.GoToAsync("StartPage");
}
}
I found the answer by watching a couple of videos by James Montemagno on youtube. If you are new to xamarin, I highly recommend these videos!
https://www.youtube.com/watch?v=ylbgWHB_gMI&t=1s - Login flow
https://www.youtube.com/watch?v=8iYpLMKE_ws&t=1067s - Shell Navigation
I have this code below to create an action bar with an integrated side bar using <Shell> so the user can navigate easily by swiping right. Being new to C#, I understand that the first ShellContent is gonna be the page to be loaded and previewed by the <Shell> when the app opens which is ContentTemplate="{DataTemplate local:LoanHistory}"
I also understand when you click on the FlyoutItems you aren't gonna add stack to the navigation but the <Shell> is changing the contents each time you click on it. This code below is in a file called MainPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:LoanApp2.Views"
mc:Ignorable="d"
x:Class="LoanApp2.MainPage" BackgroundColor="#62bef0" Title="Dylan">
<FlyoutItem Title="MyTabApp" Shell.TabBarIsVisible="False" FlyoutDisplayOptions="AsMultipleItems">
<ShellContent Title="Loan History" IsTabStop="False" ContentTemplate="{DataTemplate local:LoanHistory}"/>
<ShellContent Title="Apply for Loan" IsTabStop="False" ContentTemplate="{DataTemplate local:LoanApplication}"/>
<ShellContent Title="Logout" IsTabStop="False" ContentTemplate="{DataTemplate local:LoanHistory}"/>
</FlyoutItem>
</Shell>
So, via the side bar (shell) - I click on Apply for Loan which takes me to LoanApplication.xaml. By this time, no stack is added to the navigation. In the LoanApplication.xaml, I'm using PushAsync binded to a button to take me to a page called AmountLoanable.xaml. This gets added to the stack and the back button on the action bar is now available.
After I am done with the stuff on AmountLoanable.xaml, I use PopToRootAsync to remove the navigation stack except for the root page (which is the <Shell>, MainPage.xaml). However, it takes me back to the "Apply for Loan" which was selected prior, what I want to happen is for it to load a fresh new <Shell>, MainPage.xaml page. In that way, the first page (Loan History) will be the one selected instead of the last page accessed via <Shell>
try to reset your Application.Current.MainPage to your default Shell ex: Application.Current.MainPage = new AppShell();
I'm having a problem with how to implement navigation to pages that are not represented in shell visual hierarchy (defined in my Shell xaml).
From what I read about Shell navigation in the docs, there are two ways I can navigate to such a page:
Using the Navigation property:
Navigation.PushAsync(new TargetPage());
Registering a route and using Shell's URI navigation:
Routing.RegisterRoute("targetPageRoute", typeof(TargetPage));
Shell.Current.GoToAsync("targetPageRoute");
Both methods encounter the same problem: Once you use either method to navigate to a page outside the visual hierarchy, normal navigation between Shell's flyoutItems (using the flyout menu) will crash the app with the error:
System.Collections.Generic.KeyNotFoundException: The given key 'MyProject.TargetPage' was not present in the dictionary.
How to reproduce:
Add two items to Shell's visual hierarchy:
<FlyoutItem Title="page 1">
<Tab>
<ShellContent>
<local:Page1 />
</ShellContent>
</Tab>
</FlyoutItem>
<FlyoutItem Title="page 2">
<Tab>
<ShellContent>
<local:Page2 />
</ShellContent>
</Tab>
</FlyoutItem>
Use a button on Page1 to navigate to Page3 (a page not defined above) using either of the two ways to navigate described at the top of this post:
private void Button_Clicked(object sender, EventArgs e) {
Navigation.PushAsync(new Page3());
}
Use the flyout menu to navigate to Page2
Use the flyout menu to navigate to Page1 - the app should now crash.
I have tested this in my main project and in a small test project extensively and cant seem to find a solution. Any help would be greatly appreciated.
Here's the same issue from xamarin forms' github: https://github.com/xamarin/Xamarin.Forms/issues/6738
Also, if you scroll down, you'll see pull request, which actually resolves the problem (already helped our company's application).
You have to implement a custom renderer, which is going to inherit from ShellItemRenderer, and override the existing HandleFragmentUpdate (because of the fact, that it uses private fields from the original ShellItemRendererBase, you'll have to rebase them here too (not override, just copy them from current xamarin android ShellItemRendererBase.cs file)).
BUT, as the official docs suggest, you shall not just assign this renderer to a ShellItem derivative, instead, you'll have to create custom ShellRenderer with overriding it's CreateShellItemRenderer method (so it would create your fixed shell item renderer instead of the default one). You just apply this renderer to a custom shell control in xamarin forms.
Of course, everything you do now is temporary, until xamarin pushes new update with this fix included...
you could try to change the shell.xaml like this:
<FlyoutItem FlyoutDisplayOptions="AsMultipleItems">
<Tab Title="page 1">
<ShellContent >
<local:Page1 />
</ShellContent>
</Tab>
<Tab Title="page 2">
<ShellContent >
<local:Page2 />
</ShellContent>
</Tab>
</FlyoutItem>
Have you tried to add your Route before setting the BindingContext ?
For Example :
public NavigationShell()
{
Routing.RegisterRoute("targetPageRoute", typeof(TargetPage));
BindingContext = this;
}