Custom layout, Xamarin forms. Best approach - c#

I'm new to Xamarin.Forms and Xaml and this. I have made a custom control i would like to utilize as a custom background throughout my app. The custom control is made as a contentview and looks like this.
<ContentView.Content>
<ScrollView>
<StackLayout>
<RelativeLayout Padding="0" BackgroundColor="Teal" VerticalOptions="Start">
<Image Source="TopBG" BackgroundColor="Purple" Aspect="Fill" RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=1}" RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=0.6}" />
</RelativeLayout>
<Frame Padding="0" Margin="0,-25,0,0" CornerRadius="25" BackgroundColor="{StaticResource Key=Charcoal}">
<StackLayout Margin="0,0,0,0" VerticalOptions="StartAndExpand" BackgroundColor="Transparent" x:Name="InnerStack">
<!--I can insert custom controls here, but htat would determine this custom contentView for one purpose only-->
</StackLayout>
</Frame>
</StackLayout>
</ScrollView>
</ContentView.Content>
The custom control is then implemented on my ContentPage as such:
<ContentPage.Content>
<CustomLayouts:ContentBackground>
<!-- I would instead like to be able to add content here, and have it go into the stacklayout of the custom view.
This way i could utilize the same background but have different content go into it depending on my wishes -->
</CustomLayouts:ContentBackground>
</ContentPage.Content>
If i add a label inside that later example it just overrides everything and places a label, but not as intended inside the designated inner stackview of my ContentBackground.
The only thing i can think of is figuring some way of accesing the InnerStackView of my custom contentBackground, then accesing the children property of that Stacklayout and then Children.add(View) to that stack layout. Allthough this means i will have to do it from code and i would like to achieve this behaviour in XAML since that is more familiar to me.
Is this the only way or is there an alternative to achieve my goal in XAML?

Try use ContentProperty.Simple example:
[ContentProperty("AddContent")]
public class YourView: ContentView
{
protected ContentView ContentContainer;
public View AddContent
{
get => ContentContainer.Content;
set => ContentContainer.Content = value;
}
......
}
//in xaml
<YourView>
<Label Text="Hello world"/>
</YourView>

In case someone still trying this, you can use ControlTemplate to have a view on multiple pages or app wide,
<Application xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="SimpleTheme.App">
<Application.Resources>
<ResourceDictionary>
<ControlTemplate x:Key="TealTemplate">
<Grid>
...
<BoxView ... />
<Label Text="Control Template Demo App"
TextColor="White"
VerticalOptions="Center" ... />
<ContentPresenter ... />
<BoxView Color="Teal" ... />
<Label Text="(c) Xamarin 2016"
TextColor="White"
VerticalOptions="Center" ... />
</Grid>
</ControlTemplate>
<ControlTemplate x:Key="AquaTemplate">
...
</ControlTemplate>
</ResourceDictionary>
</Application.Resources>
</Application>
The magic here is the ContentPresenter, you can place anything inside it will appear just fine. Then to use the desired template, set it for your ContentView.ControlTemplate like so,
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="SimpleTheme.HomePage">
<ContentView x:Name="contentView" Padding="0,20,0,0"
ControlTemplate="{StaticResource TealTemplate}">
<StackLayout VerticalOptions="CenterAndExpand">
<Label Text="Welcome to the app!" HorizontalOptions="Center" />
<Button Text="Change Theme" Clicked="OnButtonClicked" />
</StackLayout>
</ContentView>
</ContentPage>
Checkout the official docs here.
If you want to create a custom control/layout that you can insert on any page, then you can create your own ContentView with ContentPresenter that will hold your views children,
<!-- Content -->
<ContentPresenter Content="{Binding SomeContent}"/>
where SomeContent can be a BindableProperty of type View.
You can also see an example of custom layouts here.

Related

Xamarin View - How to put TextButton to the foreground of google map

I want to put my text button "login" to the foreground and into the google maps view. The aqua color should not be visible.
This question is related to Xamarin View - How to put TextButton at the end and to the foreground, but actually does not solve my problem with google maps.
<?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="StandApp.Views.MainMapPage"
xmlns:maps="clr-namespace:Xamarin.Forms.GoogleMaps;assembly=Xamarin.Forms.GoogleMaps"
Title="MapsPage1">
<ContentPage.Content>
<StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"
HeightRequest="1" BackgroundColor="Aqua">
<maps:Map x:Name="map" MyLocationEnabled="True" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand"/>
<StackLayout Padding="10, 10, 10, 10">
<Button VerticalOptions="Center" Text="Login" />
</StackLayout>
</StackLayout>
</ContentPage.Content>
</ContentPage>
My current state looks like this:
use a Grid with two rows. Make the Map span both rows, then add the Button to only the 2nd row, on top of the map
<Grid RowDefinitions="80*,20*">
<Map Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" ... />
<Button Grid.Row="1" Grid.Column="0" ... />
</Grid>

Xamarin.Forms Navigation.PushAsync as Side Menu

I am using Xamarin.Forms and I have 2 pages, one is a List View, the other is a just a view I am using as a filter for the List View. I am currently using Navigation.PushAsync to display this page, my question is, is there away to present it like a side menu? I know there is Master Detail View which I am already using for the main menu and I dont think I can have 2 Master Details in my app, I tried that approach but it adds an additional navigation.
Here is my code.
public partial class PatientsPage : ContentPage
{
public PatientsPage()
{
InitializeComponent();
ToolbarItems.Add(new ToolbarItem("Filter", "filter.png", () => { openFilter(); }));
}
public async void openFilter()
{
await Navigation.PushAsync(new PatientFiltersPage());
}
}
UPDATE
Is there away to have 2 details in 1 master to accomplish this? I really don't want to use a 3rd party library.
I personally do not know of
any way to have 2 details in 1 master
According to the documentation:
The Xamarin.Forms MasterDetailPage is a page that manages two related pages of information – a master page that presents items, and a detail page that presents details about items on the master page.
So in theory only one Detail page is allowed per Master page (although the detail page can be a NavigationPage itself).
But if you are flexible about how to approach your problem, i would suggest using an overlay with AbsoluteLayout.
As an example, look at the image below, where i have a view over the main CollectionView that can be shown or hidden by tapping on the "Filter" button:
Of course you can get as creative as you want, and make the view appear sliding from below, or from the side, or fading in: there is a robust support for animations in Xamarin.Forms. Also the view can be scrollable so that if you have a variety of filters you do not cover the whole CollectionView with the Filter.
If that kind of solution is tolerable, you can achieve it as follows:
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="FilterDetail.StartPage">
<ContentPage.ToolbarItems>
<ToolbarItem Text="Filter"
Clicked="ToolbarItem_Clicked"/>
</ContentPage.ToolbarItems>
<ContentPage.Content>
<AbsoluteLayout>
<CollectionView x:Name="listView" AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Frame Margin="15">
<Label Text="{Binding .}"/>
</Frame>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<ContentView x:Name="FilterOverlay"
IsVisible="True" VerticalOptions="End"
AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All"
BackgroundColor="Transparent">
<Frame CornerRadius="10"
Margin="10"
HorizontalOptions="FillAndExpand" InputTransparent="False">
<StackLayout Padding="0">
<Label x:Name="FilterText"
Text="Filter Options"
FontSize="Medium"
TextColor="Black"/>
<StackLayout Orientation="Horizontal"
HorizontalOptions="CenterAndExpand">
<Label Text="Filter key 1"/>
<Switch IsToggled="True" />
</StackLayout>
<StackLayout Orientation="Horizontal"
HorizontalOptions="CenterAndExpand">
<Label Text="Filter key 2"/>
<Switch IsToggled="True" />
</StackLayout>
<StackLayout Orientation="Horizontal"
HorizontalOptions="CenterAndExpand">
<Label Text="Filter key 3"/>
<Switch IsToggled="False" />
</StackLayout>
<StackLayout Orientation="Horizontal"
HorizontalOptions="CenterAndExpand">
<Label Text="Filter key 4"/>
<Switch IsToggled="True" />
</StackLayout>
<Button Text="Apply"
HeightRequest="30"
Padding="0"
BackgroundColor="Accent"/>
</StackLayout>
</Frame>
</ContentView>
</AbsoluteLayout>
</ContentPage.Content>
</ContentPage>
Code behind
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace FilterDetail
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class StartPage : ContentPage
{
public StartPage()
{
InitializeComponent();
var items = new List<String>();
for (int i = 0; i < 1000; i++)
items.Add($"Item {i}");
listView.SetBinding(CollectionView.ItemsSourceProperty, new Binding() { Source = items, Path = "." });
}
private void ToolbarItem_Clicked(object sender, EventArgs e)
{
FilterOverlay.IsVisible = !FilterOverlay.IsVisible;
}
}
}
Update
In order to simulate a second Master/Menu we can simply modify our solution presented above in order to expand our overlay vertically and add some animation so that instead of simply appear and disappear, the overlay hides to the right.
Let's see how this is done:
The Overlay
Add an overlay that covers the whole screen except from a margin on the left so that it looks like a Master Menu.
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="FilterDetail.StartPage">
<ContentPage.ToolbarItems>
<ToolbarItem Text="Filter"
Clicked="ToolbarItem_Clicked"/>
</ContentPage.ToolbarItems>
<ContentPage.Content>
<AbsoluteLayout>
<CollectionView x:Name="listView" AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Frame Margin="15">
<Label Text="{Binding .}"/>
</Frame>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<ContentView x:Name="FilterOverlay"
IsVisible="True"
AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All"
BackgroundColor="Transparent">
<Frame CornerRadius="10"
Margin="100,10,0,10"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
InputTransparent="False">
<StackLayout Padding="0">
<Label x:Name="FilterText"
Text="Filter Options"
FontSize="Medium"
TextColor="Black"/>
<StackLayout Orientation="Horizontal"
HorizontalOptions="CenterAndExpand">
<Label Text="Filter key 1"/>
<Switch IsToggled="True" />
</StackLayout>
<StackLayout Orientation="Horizontal"
HorizontalOptions="CenterAndExpand">
<Label Text="Filter key 2"/>
<Switch IsToggled="True" />
</StackLayout>
<StackLayout Orientation="Horizontal"
HorizontalOptions="CenterAndExpand">
<Label Text="Filter key 3"/>
<Switch IsToggled="False" />
</StackLayout>
<StackLayout Orientation="Horizontal"
HorizontalOptions="CenterAndExpand">
<Label Text="Filter key 4"/>
<Switch IsToggled="True" />
</StackLayout>
<Button Text="Apply"
HeightRequest="30"
Padding="0"
BackgroundColor="Accent"
VerticalOptions="EndAndExpand"/>
</StackLayout>
</Frame>
</ContentView>
</AbsoluteLayout>
</ContentPage.Content>
</ContentPage>
Next, add some animation to ToolbarItem_Clicked so that on tapping the Filter toolbar item, the overlay
hides to the right
Code Behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace FilterDetail
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class StartPage : ContentPage
{
public StartPage()
{
InitializeComponent();
var items = new List<String>();
for (int i = 0; i < 1000; i++)
items.Add($"Item {i}");
listView.SetBinding(CollectionView.ItemsSourceProperty, new Binding() { Source = items, Path = "." });
}
private async void ToolbarItem_Clicked(object sender, EventArgs e)
{
if (FilterOverlay.IsVisible)
{
// If overlay is visible, slide it to the right, and set as invisible.
await FilterOverlay.TranslateTo(this.Width-100, FilterOverlay.Y);
FilterOverlay.IsVisible = false;
}
else
{
// If overlay is invisible, make it visible and slide to the left.
FilterOverlay.IsVisible = true;
await FilterOverlay.TranslateTo(0, FilterOverlay.Y);
}
}
}
}
And that's it. The result looks like this:
Of course this is only a sample, and a bit of extra work on the overlay and on the animation can give you amazing results. Enjoy!

Can you surround content with a custom view

I have a bunch of code in a page that I would like to make reusable across multiple pages
<StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<SwipeView x:Name="MainSwipeView" BackgroundColor="Transparent"
SwipeStarted="SwipeStarted" SwipeEnded="SwipeEnded" VerticalOptions="FillAndExpand">
<SwipeView.LeftItems>
</SwipeView.LeftItems>
<Grid x:Name="swipeContent">
Where I want the rest of the content to be
(This means this would surround the content, similar to <ContentPresenter/> in a ControlTemplate)
</Grid>
</SwipeView>
<StackLayout HeightRequest="50" BackgroundColor="Red">
<Label> Where the Augnito Button will be </Label>
</StackLayout>
</StackLayout>
I wanted to put this in a reusable component so I could use it in other pages as follows:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
.
.
.
.>
<MyReusableComponent>
<StackLayout>
This is where the regular contents of a page would go
</StackLayout>
</MyReusableComponent>
</ContentPage>
I don't think I can use a ControlTemplate because my custom view has code behind it in a xaml.cs file to make it work, so is there another way to do this?

Menu home page background color

I am using a NavigationPage.TitleView control on my home page but it looks like there is a problem filling the whole title section. The HamburgerMenu icon is coming from the menupage.xaml and that background color is not getting set?
Do I need to get a new icon with that background Color I need?
homepage.xaml
<NavigationPage.TitleView>
<StackLayout Orientation="Horizontal" BackgroundColor="#22335c">
<Label Text="N" HorizontalOptions="FillAndExpand" VerticalOptions="CenterAndExpand" BackgroundColor="#22335c" TextColor="White" />
<Image Source="" Aspect="AspectFit" BackgroundColor="#22335c" />
</StackLayout>
</NavigationPage.TitleView>
Menupage.xaml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MenuPage"
xmlns:telerikPrimitives="clr-namespace:Telerik.XamarinForms.Primitives;assembly=Telerik.XamarinForms.Primitives"
xmlns:telerik="clr-namespace:Telerik.XamarinForms.DataControls;assembly=Telerik.XamarinForms.DataControls"
xmlns:model="clr-namespace:ReimbursementApp.Model"
xmlns:page="clr-namespace:ReimbursementApp.Pages"
Title="Menu" Icon="HamburgerMenu.png" BackgroundColor="Black">

Set navigation side menu background image in Xamarin Forms

In Xamarin forms I want to use an image ( png file ) I created as background for a side "hamburger" menu. For example, here is some menu:
Two questions:
1) What's the best image size to use for the menu background
2) How do I put a ListView that contains my menu options on top of the background image ?
I tried using the grid but wasn't successful at stacking them. Code below is a quick summary of how the MasterDetailPage is structured.
//Menu
<MasterDetailPage.Master>
<ContentPage>
<ContentPpage.Content>
<AbsoluteLayout> //Also tried FlexLayout and RelativeLayout
<Image Source="blah" Aspect="Fill"/>
<Grid>
<ListView/>
</Grid>
</AbsoluteLayout>
</ContentPpage.Content>
<ContentPage>
</MasterDetailPage.Master>
//Page content
<MasterDetailPage.Detail>
<ContentPage>
///Page content
</ContentPage>
</MasterDetailPage.Detail>
The goal is to get the side menu looking something like this:
I just tried one sample solution. This is my master page :
<?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:local="using:MasterDetailPageNavigation"
x:Class="MasterDetailPageNavigation.MasterPage"
Padding="0,40,0,0"
Icon="hamburger.png"
Title="Personal Organiser">
<Grid>
<Image Source="Default-Portrait.png" Aspect="AspectFill" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"/>
<StackLayout Margin="0,20,0,0">
<ListView x:Name="listView" x:FieldModifier="public" BackgroundColor="Transparent">
<ListView.ItemsSource>
<x:Array Type="{x:Type local:MasterPageItem}">
<local:MasterPageItem Title="Contacts" IconSource="contacts.png" TargetType="{x:Type local:ContactsPage}" />
<local:MasterPageItem Title="TodoList" IconSource="todo.png" TargetType="{x:Type local:TodoListPage}" />
<local:MasterPageItem Title="Reminders" IconSource="reminders.png" TargetType="{x:Type local:ReminderPage}" />
</x:Array>
</ListView.ItemsSource>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Padding="5,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Source="{Binding IconSource}" />
<Label Grid.Column="1" Text="{Binding Title}" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</Grid>
</ContentPage>
There is a trick to have Grid as a parent. If you put 2 controls in same Cell it will overlap. Here my background image "Default-Portrait" will get overlapped by my StackLayout (listview) which has Background Color set as "Transparent".
For the Size of the Image, I would use multiple Size and put those images in the appropriate drawable-hdpi directory in android and iOS assets.
Let me know if you need any more clarifications.
This is a result:

Categories