I'm building a mobile app as a learning/hobby project and was curious about how far I can push the designs in a xamarin app. Is there a way to present a consistent backplane or image in an app that employs MasterDetailPage in the mainview? The effect I'm trying to accomplish is when each page is shown, which would have a transparent background, the app background never changes or is part of the page transition at all.
A.
Since any page type (Shell, NavigationPage, ContentPage, etc) that derives from Page has a BackgroundImageSource property, you can define the value globally in App.xaml.
<Application.Resources>
<Style ApplyToDerivedTypes="True" TargetType="Page">
<Setter Property="BackgroundImageSource" Value="your_image.png" />
</Style>
</Application.Resources>
B.
Well, if you wanna apply it just for MasterDetail pages, you can just set the style for NavigationPage only.
<Application.Resources>
<Style TargetType="NavigationPage">
<Setter Property="BackgroundImageSource" Value="your_image.png" />
</Style>
</Application.Resources>
If you want all the pages in your project has the same background, you can create a BaseContentPage which have a background image or backgroundColor and then all other pages inherits from the BaseContentPage :
BaseContentPage:
public class BasePage : ContentPage
{
public BasePage()
{
this.BackgroundImageSource = "logo.jpg";
}
}
Other pages in your project:
public partial class Page1 : BasePage
{
public Page1()
{
InitializeComponent();
}
}
In Xaml:
<?xml version="1.0" encoding="utf-8" ?>
<xaminals:BasePage xmlns:xaminals="clr-namespace:Xaminals"
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"
mc:Ignorable="d"
x:Class="Xaminals.Page1">
<xaminals:BasePage.Content>
<StackLayout>
<Label Text="Welcome to Xamarin.Forms!"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
</StackLayout>
</xaminals:BasePage.Content>
</xaminals:BasePage>
Then all the pages will have the logo image as the background image.
Related
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:
I am trying to apply background image to all pages within my Xamarin.Forms app using an application style, but it is not applying the style to the pages.
I tried with this:
App.xaml resources
...
<Application.Resources>
<ResourceDictionary>
<Style TargetType="Page">
<Setter Property="BackgroundImageSource" Value="logo.png"/>
</Style>
...
MainPage.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:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="FinansovoPregledi.MainPage">
<StackLayout Spacing="10" VerticalOptions="Center">
<Button Text="Login" BackgroundColor="#006BE6" x:Name="scanButton" TextColor="WhiteSmoke" Command="{Binding LogInCommand}"/>
</StackLayout>
</ContentPage>
MainPage.xaml.cs
public partial class MainPage : ContentPage
{
LoginViewModel loginViewModel = new LoginViewModel();
public MainPage()
{
InitializeComponent();
BindingContext = loginViewModel;
}
...
This isn't working. In my scenario the background image has a white background with transparency.
ContentPage is derived from Page and for your style to apply to Pages as well as all controls derived from Pages you need to set the ApplyToDerivedTypes property of your style to True.
Your style would need to be
<Style ApplyToDerivedTypes="True" TargetType="Page">
<Setter Property="BackgroundImageSource" Value="logo.png"/>
</Style>
Another approach would be to set the TargetType to ContentPage
<Style TargetType="ContentPage">
<Setter Property="BackgroundImageSource" Value="logo.png"/>
</Style>
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
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 />.
Custom control class:
public class CustomTextInput : UITextField
{
}
Xamarin.Forms xaml:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:Custom="clr-namespace:SampleApp.CustomControls;assembly=SampleApp"
x:Name="SampleAppView">
<ContentPage.Content>
<StackLayout Orientation="Horizontal">
<Image Source="Sample_ic.png" WidthRequest="29" HeightRequest="29"/>
<StackLayout Orientation="Vertical">
<Label Text="Sample Text" TextColor="#717073" FontSize="Small" FontFamily="Helvetica"/>
<!--Accessing IOS Custom control class-->
<Custom:CustomTextInput Text="50 Gal" BackgroundColor="Transparent" TextColor="#838288" />
</StackLayout>
</StackLayout>
</ContentPage.Content>
</ContentPage>
Can I access android/IOS custom control class in xamarin.forms xaml? For sample I used UITextField control. But I need to access android/IOS platform specific custom controls which is not available in xamarin.forms.
If you're using Xamarin.Forms, you're working with the platform independent controls. UITextField doesn't exist, but is instead mapped to an Entry.
Your best bet is to make a custom Entry subclass:
public class MyEntry : Entry
{
}
And use it in your 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"
x:Class="MyApp.SomePage"
xmlns:local="clr-namespace:MyApp;assembly=MyApp">
<local:MyEntry />
</ContentPage>
Then, on each platform, you can provide a platform specific Renderer.
[assembly:ExportRenderer (typeof(MyApp.MyEntry), typeof(MyApp.iOS.MyEntryRenderer))]
namespace MyApp.iOS
{
public class MyEntryRenderer : EntryRenderer
{
protected override void OnElementChanged (ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged (e);
if (null == Control)
return;
var textField = Control as UITextField;
// do stuff with textField
}
}
}
If you find that rendering the custom controls individually does not provide the exact level of control you need, you can also make custom Page Renderers, as seen here.