Keyboard flashes when navigating in Shell flyouts - xamarin.forms

My Xamarin.Forms app is using Shell flyouts for navigation. When I navigate the app on iOS, I notice a strange behaviour. Reproduction steps:
Go to a page that has an Entry in it
Type anything into the Entry
Go to another page
Return to the same page you typed something into the Entry
The keyboard then pops up and then disappears right after. I can see the cursor in the Entry appear then disappear too. I removed a lot of my code to try to find the problem, but I can not find it. My code:
AppShell.xaml:
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MyApp.Views"
Title="MyApp"
x:Name="shellAppShell"
x:Class="MyApp.AppShell">
<FlyoutItem x:Name="flyoutItemMainPage" Title="Home" Icon="icon_about.png">
<ShellContent x:Name="shellContentMainPage" Route="MainPage" ContentTemplate="{DataTemplate local:MainPage}" />
</FlyoutItem>
<FlyoutItem x:Name="flyoutItemAPage" Title="A Page" Icon="Pagea.png">
<ShellContent x:Name="shellContentPageA" Route="PageA" ContentTemplate="{DataTemplate local:PageA}" />
</FlyoutItem>
<!-- More flyouts... -->
</Shell>
PageA.xaml:
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Name="PageA"
x:Class="MyApp.Views.PageA">
<ContentPage.Content>
<StackLayout Orientation="Vertical" >
<Entry />
<Button Text="back" Clicked="OnBackClicked"/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
PageA.xaml.cs
public partial class PageA : ContentPage
{
public PageA()
{
InitializeComponent();
}
void OnBackClicked(object sender, EventArgs e)
{
Shell.Current.CurrentItem = AppShellGlobal.ShellContentMainPage;
}
}

After my testing, this situation only occurs in iOS.
There is a simpler solution, you can rewrite the ContentPage and end the editing state of the page when the page loads.
First, create the MyPageRenderer class in your project's xxx.iOS directory.
Here is the internal code:
[assembly: ExportRenderer(typeof(ContentPage), typeof(MyPageRenderer))]
namespace App15.iOS
{
public class MyPageRenderer : PageRenderer
{
public override void ViewDidAppear(bool animated)
{
View.EndEditing(true);//Solved the problem with this line of code
base.ViewDidAppear(animated);
}
}
}
Here is the screenshot:

Related

A part of tabbedPage is sheltered in IOS

Just a simple project of maui,it use tabbar shell
------AppShell-----
<Shell
x:Class="TABSample.AppShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:TABSample"
Shell.FlyoutBehavior="Disabled">
<TabBar>
<Tab Title="Test">
<ShellContent Title="Test1" ContentTemplate="{DataTemplate local:NewPage1}" />
<ShellContent Title="Test2" ContentTemplate="{DataTemplate local:NewPage2}" />
</Tab>
</TabBar>
</Shell>
-----NewPage1---------------
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="TABSample.NewPage1"
Title="NewPage1">
<StackLayout>
<Label
Text="Welcome to .NET MAUI!"
VerticalOptions="Center"
HorizontalOptions="Center" />
</StackLayout>
</ContentPage>
-----------Iphone 14 pro IOS 16.2------------------
enter image description here
cannot see the label text
----------Android--------------------------
enter image description here
A part of tabbedPage is sheltered in IOS, the reason is iOS Simulator? Screen content is only shown in a part of screen in iOS Simulator
but ohter page is ok
Yes I could reproduce your issue. Just as #Bas H mentioned, the control is behind the tabs. I also found the same issue in Github: Contentpage is cut off in iOS #8778. You could follow it.
For a workaround, you could set the page padding
protected override void OnAppearing()
{
base.OnAppearing();
Padding = new Thickness(0, 40, 0, 0);
}
or set like #Bas H suggested but i think use Margin is better:
<VerticalStackLayout Margin="{x:OnPlatform iOS='0,40,0,0', Android='0'}" >

TabbedPage selectedItem doesn't change when change tab programmatically to tab in "More"

I am working on a Xamarin Forms app with a TabbedPage which has 6 tabs.
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:tabs="clr-namespace:TabbedPageIssue"
xmlns:android="clr-namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
android:TabbedPage.ToolbarPlacement="Bottom"
android:TabbedPage.IsSwipePagingEnabled="False"
android:TabbedPage.BarSelectedItemColor="#F79320"
android:TabbedPage.BarItemColor="#B1B2B3"
x:Class="TabbedPageIssue.MainPage">
<tabs:Tab1 Title="Tab1"/>
<tabs:Tab2 Title="Tab2"/>
<tabs:Tab3 Title="Tab3"/>
<tabs:Tab4 Title="Tab4"/>
<tabs:Tab5 Title="Tab5"/>
<tabs:Tab6 Title="Tab6"/>
</TabbedPage>
In my app, I want to have a button to direct the app to a tab "inbox" in the "More" part with this code:
private void Button_Clicked(object sender, EventArgs e)
{
var mainPage = this.Parent as TabbedPage;
mainPage.CurrentPage = mainPage.Children[4];
}
When i click the button to change tab, the View changes but the "More" tab is not selected, and if i click on tab1, the view of tab 5 doesn't disappear.
This seems to be a bug of TabbedPage. Everybody has any idea to fix this problem?
I was able to reproduce this issue. For workaround, you could use Shell tabs instead. For the latest version of VS, when you create a Tabbed template, it is using Shell. https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/shell/
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:local="clr-namespace:App3.Views"
Title="App3"
x:Class="App3.AppShell">
<TabBar>
<ShellContent Title="Tab1" ContentTemplate="{DataTemplate local:Page1}" />
<ShellContent Title="Tab2" ContentTemplate="{DataTemplate local:Page2 }" />
<ShellContent Title="Tab3" ContentTemplate="{DataTemplate local:Page3 }" />
<ShellContent Title="Tab4" ContentTemplate="{DataTemplate local:Page4}" />
<ShellContent Title="Tab5" Route="page5" ContentTemplate="{DataTemplate local:Page5 }" />
<ShellContent Title="Tab6" ContentTemplate="{DataTemplate local:Page6 }" />
</TabBar>
</Shell>
Navigating from Page1 to Page5:
async void Button_Clicked(object sender, EventArgs e)
{
await Shell.Current.GoToAsync("//page5");//page5 is the route i set in xaml
}
OutPut:

Set default tab on Xamarin Forms Shell

How to set the default selected Tab inside the tab bar on Xamarin forms shell?
<?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="TestApp.NavigationShell"
xmlns:pages="clr-namespace:TestApp.Pages"
xmlns:pageModels="clr-namespace:TestApp.PageModels">
<TabBar Route="testapp">
<Tab Title="Saved" Icon="tabDashboard" Route="dashboard"><ShellContent ContentTemplate="{DataTemplate pages:DashBoardPage}"/></Tab>
<Tab Title="Calendar" Icon="tabCalendar" Route="calendar"><ShellContent ContentTemplate="{DataTemplate pages:CalendarPage}"/></Tab>
<Tab Title="Search" Icon="tabSearch" Route="search"><ShellContent ContentTemplate="{DataTemplate pages:SearchPage}"/></Tab>
<Tab Title="Support" Icon="tabSupport" Route="support"><ShellContent ContentTemplate="{DataTemplate pages:SupportPage}"/></Tab>
<Tab Title="Profile" Icon="tabAccount" Route="account"><ShellContent ContentTemplate="{DataTemplate pages:AccountPage}"/></Tab>
</TabBar>
According to the Xamarin Forms documentation, the first Shell Content will be the default content on the screen. However; I'm trying to set the "Search" page as the default tab rather than "Saved".
I tried to set Tab Index - no luck
I also tried to call routing on onAppearing method of Shell but seems like Shell's on appearing method never gets fired.
I tried to navigate to Search as well:
public partial class NavigationShell : Shell
{
public NavigationShell()
{
InitializeComponent();
//Shell.Current.TabIndex = 2;
}
protected override async void OnAppearing()
{
base.OnAppearing();
//await Shell.Current.GoToAsync("testapp/search");
}
}
What could be the best solution that when app opens need to set the default tab?
Thank you.
Here, how I fix it by using the Name field attribute.
I assigned the name to the TabBar and the tab which I want to assign in the first place.
AppShell.xaml
<TabBar x:Name="main_tab_bar" Route="main">
<Tab Title="History">
<Tab.Icon>
<FontImageSource FontFamily="MaterialIconsRegular" Glyph="{x:Static Emojis:MaterialRegFont.List}"/>
</Tab.Icon>
<ShellContent ContentTemplate="{DataTemplate Views:CallLogPage}" />
</Tab>
<Tab x:Name="main_tab_bar_dial" Title="Dial" >
<Tab.Icon>
<FontImageSource FontFamily="MaterialIconsRegular" Glyph="{x:Static Emojis:MaterialRegFont.Dialpad}"/>
</Tab.Icon>
<ShellContent ContentTemplate="{DataTemplate Views:MainDialerPage}" />
</Tab>
<Tab Title="Settings">
<Tab.Icon>
<FontImageSource FontFamily="MaterialIconsRegular" Glyph="{x:Static Emojis:MaterialRegFont.Settings}"/>
</Tab.Icon>
<ShellContent ContentTemplate="{DataTemplate Views:MainSettingsPage}" />
</Tab>
</TabBar>
AppShell.cs
public AppShell() {
InitializeComponent();
Init();
}
private void Init() {
main_tab_bar.CurrentItem = main_tab_bar_dial;
}
Nevermind, I think I found a solution.
public Page Init(Shell root)
{
CurrentShell = root;
root.CurrentItem.CurrentItem = root.CurrentItem.Items[2];
return CurrentShell;
}
Becase my shell have ONLY one root item which is tabbar itself. I just get the search tab and assigned to the first child's current item and it worked.
Please post your answers if you found another way around.
Thank you.
On the constructor of your Shell class you can set the CurrentItem
in my case I have an <ShellItem> with some <tab>
public PrivateShell()
{
InitializeComponent();
this.CurrentItem.CurrentItem = homeTab; //tab defined by x:Name on XAML
}
As far as I could check it does not pre-render the first shellcontent in case you're using ContentTemplate pattern

Xamarin.Forms: How to hide the Navigation Bar Separator on iOS devices?

I have changed the default color of the navigation bar by using these codes in app.xaml as I am unable to make it transparent on iOS devices:
<Style TargetType="NavigationPage">
<Setter Property="BarBackgroundColor" Value="#0a82b8" />
<Setter Property="BarTextColor" Value="#ffffff" />
</Style>
Now, there is an unnecessary navigation bar separator on iOS:
On Microsoft's official website, it says these codes can be helpful:
This platform-specific hides the separator line and shadow that is at
the bottom of the navigation bar on a NavigationPage. It's consumed in
XAML by setting the NavigationPage.HideNavigationBarSeparator bindable
property to false:
<NavigationPage ...
xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
ios:NavigationPage.HideNavigationBarSeparator="true">
</NavigationPage>
Alternatively, it can be consumed from C# using the fluent API:
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
public class iOSTitleViewNavigationPageCS : Xamarin.Forms.NavigationPage
{
public iOSTitleViewNavigationPageCS()
{
On<iOS>().SetHideNavigationBarSeparator(true);
}
}
Source: Hiding the Navigation Bar Separator on a NavigationPage
The problem is that when I want to paste the ios:NavigationPage.HideNavigationBarSeparator="true" property into the <NavigationPage>tag, it gives this error:
No property, bindable property, or event found for 'HideNavigationBarSeparator', or mismatching type between value and property.
My full codes are:
<?xml version="1.0" encoding="utf-8"?>
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:My.App" x:Class="My.App.MainPage">
<MasterDetailPage.Master>
<ContentPage Title="Menu" BackgroundColor="#0a82b8" Icon="menu.png">
<StackLayout Orientation="Vertical">
<ListView x:Name="navigationDrawerList" RowHeight="55" SeparatorVisibility="None" BackgroundColor="#ffffff" ItemSelected="OnMenuItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<!-- Main design for our menu items -->
<StackLayout VerticalOptions="FillAndExpand" Orientation="Horizontal" Padding="20,10,0,10" Spacing="20">
<Label Text="{Binding Title}" FontSize="Large" VerticalOptions="Start" HorizontalOptions="CenterAndExpand" TextColor="#28DDFF" FontAttributes="Bold" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
</MasterDetailPage.Master>
<MasterDetailPage.Detail>
<NavigationPage xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
ios:NavigationPage.HideNavigationBarSeparator="true">
</NavigationPage>
</MasterDetailPage.Detail>
</MasterDetailPage>
Here is the tutorial which I followed for the MasterDetail navigation. The file which has <NavigationPage> tag is named as MainPage.xaml
You can use a custom renderer to hide that shadow:
[assembly: ExportRenderer(typeof(NavigationPage), typeof(CustomNavigationPage))]
namespace CustomNavigationPage.iOS
{
public class CustomNavigationPage : NavigationRenderer
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
NavigationBar.SetBackgroundImage(new UIKit.UIImage(), UIKit.UIBarMetrics.Default);
NavigationBar.ShadowImage = new UIKit.UIImage();
}
}
}
While you have accepted the answer, this one is more precise - you haven't followed the instructions that you have pasted from the site as you have ommited this line:
xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
Place UINavigationBar.Appearance.ShadowImage = new UIImage(); inside the public override bool FinishedLaunching(UIApplication app, NSDictionary options) method within AppDelegate.cs file. AppDelegate.cs resides within the iOS project of Xamarin.Forms

Xamarin.Forms: Can I embed one ContentPage or ContentView into another ContentPage

I have multiple ContentPage xaml files in my Xamarin project. I want to embed a shared piece of xaml into each ContentPage. There is nothing particularly special about the shared piece of xaml (it does't need to do anything platform specific). Shouldn't it be just as easy as embedding a tag in the xaml of the ContentPage to include the shared xaml file? Can someone point me in the right direction?
Thank you very much IdoT, It did work for me, but after adding some lines.
As this will help in making templates/custom controls/sub forms, easily added/shared across Xamarin.Forms.
Here is my full work based on your suggestion, so it can be used as is with others:
HeaderNavigationBar.xaml
<?xml version="1.0" encoding="utf-8" ?>
<StackLayout xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="App9.MVC.Views.HeaderNavigationBar"
Orientation="Horizontal"
HorizontalOptions="FillAndExpand"
Padding="10"
ackgroundColor="White">
<Button Text="Internal 1" />
<Button Text="Internal 2" />
</StackLayout>
As you can see, added:
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
and in the HeaderNavigationBar.cs, it was declared as StackLayout:
HeaderNavigationBar.cs
using Xamarin.Forms;
namespace App9.MVC.Views
{
public partial class HeaderNavigationBar : StackLayout
{
public HeaderNavigationBar()
{
InitializeComponent();
}
}
}
then for the page that will hold it/show it:
MainView.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:common="clr-namespace:App9.MVC.Views;assembly=App9"
x:Class="App9.MVC.Views.MainView">
<StackLayout Padding="0,0,0,20">
<common:HeaderNavigationBar>
<Button Text="External 1" />
</common:HeaderNavigationBar>
<Button Text="Test Button 1
x:Name="btnPage1"
Clicked="btnPage1_clicked" />
</StackLayout>
</ContentPage>
As you can notice, the namespace has the full path, in the MainView:
xmlns:common="clr-namespace:App9.MVC.Views;assembly=App9"
Also, you can notice that there is a button called External 1, this will also show with the
Internal buttons, as the control is a StackLayout, so it can handle adding more controls.
Screenshot:
Also for Page inside another Page:
https://github.com/twintechs/TwinTechsFormsLib
http://blog.twintechs.com/advanced-xamarin-forms-techniques-for-flexible-and-performant-cross-platform-apps-part-5-page-in-page-embedding
Again thanks goes to IdoT.
You can take the parent child of your ContentPage (for example, a StackLayout that wraps all the children), put it in an external xaml file,
and then include that component in each one of your ContentPages.
The external xaml file will be a StackLayout type, rather than a ContentPage.
Edit - added a code sample:
Let's add a header StackLayout: we add a code behind class:
public partial class HeaderNavigationBar
{
public HeaderNavigationBar()
{
InitializeComponent();
}
}
Then add the XAML code:
<StackLayout x:Class="HeaderNavigationBar"
Orientation="Horizontal"
HorizontalOptions="FillAndExpand"
Padding="10"
BackgroundColor="White">
<Image Source="burger_icon"
HorizontalOptions="StartAndExpand"
Aspect="AspectFit">
<Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding SlideNavigationDrawerCommand}" />
</Image.GestureRecognizers>
</Image>
</StackLayout>
And finally, in the page where you want to reuse your component - add this reference:<HeaderNavigationBar />.

Resources