Forget ToolbarItem you don’t need it any more.

We help lots of custom to create their own Apps. In their designs, the navigation bar can be any style. Some custom doesn’t want the icon in navigation bar, some customer wants to put ToolbarItem in to left, some custom wants to change Page title’s font. In the old time, I was tired to change them by custom renderer, in iOS is OK, but in Android, it’s very hard to change layout of navigation bar.

Until one day, I came up a idea, why not use a full screen page and put all ToolbarItem into a view, then use Control Template to apply them to all pages? In that view we can do whatever we want.

I tried control template, but I found it hard to change different layouts by different pages, unless you create many templates.

How about we do like ListView, it has Header and Footer, put views into them. So I create a BasePage class, use Grid layout and it works, beyond this I also put pop-up view into BasePage. Cause this custom ask me to change the alert window designs.

After finish that, I’m very happy with using that, I can do binding, change layout, do custom navigation and pop-up different windows.

Then I think of should I put into FreshEssential?

We create it, when I maintain it I found lot feature requests are add API to change some control’s font, or change some default color. That is not good, I mean the API designs is not good, it should allow user to change everything they want, but if I allow user to change everything, it means I need to put more logic to keep it works fine and test every scenarios.

So in this time, I decide to share code instead of put it into Nuget. Two reasons, one the code is small and logic is simple, another the alert window has a lots of style we can change.

The code I put on Github,

using System;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace {YOURNAMESPACE}
{
public class BasePage : ContentPage
{
ContentView _header;
public ContentView Header
{
get
{
return _header;
}
set
{
if (_mainLayout != null)
{
if (_header != null && _mainLayout.Children.Contains(_header))
_mainLayout.Children.Remove(_header);
_header = value;
if (Device.OS == TargetPlatform.iOS)
_mainLayout.Children.Add(_header, 0, 1);
else
_mainLayout.Children.Add(_header, 0, 0);
}
}
}
ContentView _footer;
public ContentView Footer
{
get
{
return _footer;
}
set
{
if (_mainLayout != null)
{
if (_footer != null && _mainLayout.Children.Contains(_footer))
_mainLayout.Children.Remove(_footer);
_footer = value;
if (Device.OS == TargetPlatform.iOS)
_mainLayout.Children.Add(_footer, 0, 3);
else
_mainLayout.Children.Add(_footer, 0, 2);
}
}
}
ContentView _content;
public ContentView ContentPresenter
{
get
{
return _content;
}
set
{
if (_mainLayout != null)
{
if (_content != null && _mainLayout.Children.Contains(_content))
_mainLayout.Children.Remove(_content);
_content = value;
if (Device.OS == TargetPlatform.iOS)
_mainLayout.Children.Add(_content, 0, 2);
else
_mainLayout.Children.Add(_content, 0, 1);
}
}
}
ContentView _popUpView;
BoxView _maskView;
public ContentView PopUpView
{
get
{
return _popUpView;
}
set
{
if (_mainLayout != null)
{
if (_maskView != null && _mainLayout.Children.Contains(_maskView))
_mainLayout.Children.Remove(_maskView);
if (_popUpView != null && _mainLayout.Children.Contains(_popUpView))
_mainLayout.Children.Remove(_popUpView);
_popUpView = value;
if (_popUpView == null)
return;
if (_maskView == null)
_maskView = new BoxView { Color = Color.Black.MultiplyAlpha(0.5), IsVisible = false };
if (Device.OS == TargetPlatform.iOS)
_mainLayout.Children.Add(_maskView, 0, 1, 0, 4);
else
_mainLayout.Children.Add(_maskView, 0, 1, 0, 3);
_popUpView.IsVisible = false;
if (Device.OS == TargetPlatform.iOS)
_mainLayout.Children.Add(_popUpView, 0, 1, 0, 4);
else
_mainLayout.Children.Add(_popUpView, 0, 1, 0, 3);
}
}
}
public static readonly BindableProperty ShowPopupProperty = BindableProperty.Create(nameof(ShowPopup), typeof(bool), typeof(BasePage), default(bool));
public bool ShowPopup
{
get { return (bool)GetValue(ShowPopupProperty); }
set { SetValue(ShowPopupProperty, value); }
}
Grid _mainLayout;
public BasePage()
{
NavigationPage.SetHasNavigationBar(this, false);
_mainLayout = new Grid
{
Padding = new Thickness(0),
RowSpacing = 0,
};
if (Device.OS == TargetPlatform.iOS)
_mainLayout.RowDefinitions.Add(new RowDefinition { Height = new GridLength(20, GridUnitType.Absolute) });
_mainLayout.RowDefinitions.Add(new RowDefinition { Height = new GridLength(44, GridUnitType.Absolute) });
_mainLayout.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
_mainLayout.RowDefinitions.Add(new RowDefinition { Height = new GridLength(44, GridUnitType.Absolute) });
Content = new ContentView { Content = _mainLayout };
}
protected override void OnPropertyChanged(string propertyName = null)
{
base.OnPropertyChanged(propertyName);
if (propertyName == ShowPopupProperty.PropertyName)
{
if (_maskView != null && PopUpView != null)
{
_maskView.IsVisible = ShowPopup;
_popUpView.IsVisible = ShowPopup;
}
}
}
public Task<bool> ShowAlert(FormattedString message, string rightButtonText = null, string leftButtonText = null, string middleButtonText = null)
{
var mainLaout = new Grid
{
RowSpacing = 0,
RowDefinitions = new RowDefinitionCollection {
new RowDefinition{Height = new GridLength(1, GridUnitType.Star)},
new RowDefinition{Height = new GridLength(1, GridUnitType.Absolute)},
new RowDefinition{Height = new GridLength(40, GridUnitType.Absolute)},
},
ColumnDefinitions = new ColumnDefinitionCollection
{
new ColumnDefinition{Width = new GridLength(1, GridUnitType.Star)},
new ColumnDefinition{Width = new GridLength(1, GridUnitType.Star)},
new ColumnDefinition{Width = new GridLength(1, GridUnitType.Star)},
}
};
var messageLabel = new Label
{
HorizontalTextAlignment = TextAlignment.Center,
VerticalTextAlignment = TextAlignment.Center,
FormattedText = message,
Margin = new Thickness(10),
};
mainLaout.Children.Add(messageLabel, 0, 3, 0, 1);
var line = new BoxView { Color = Color.Black, HeightRequest = 1 };
mainLaout.Children.Add(line, 0, 3, 1, 2);
var background = new BoxView { Color = Color.FromHex("#F7F7F7") };
mainLaout.Children.Add(background, 0, 3, 2, 3);
TaskCompletionSource<bool> completionSource = null;
if (!string.IsNullOrEmpty(leftButtonText))
{
var leftButton = new Button
{
BackgroundColor = Color.FromHex("#F7F7F7"),
Text = leftButtonText,
TextColor = Color.FromHex("#06A2D5"),
};
completionSource = new TaskCompletionSource<bool>();
leftButton.Clicked += (sender, e) =>
{
completionSource.SetResult(false);
ShowPopup = false;
};
mainLaout.Children.Add(leftButton, 0, 1, 2, 3);
}
if (!string.IsNullOrEmpty(middleButtonText))
{
var middleButton = new Button
{
BackgroundColor = Color.FromHex("#F7F7F7"),
Text = middleButtonText,
TextColor = Color.FromHex("#06A2D5"),
};
completionSource = new TaskCompletionSource<bool>();
middleButton.Clicked += (sender, e) =>
{
completionSource.SetResult(true);
ShowPopup = false;
};
mainLaout.Children.Add(middleButton, 1, 2, 2, 3);
}
if (!string.IsNullOrEmpty(rightButtonText))
{
var rightButton = new Button
{
BackgroundColor = Color.FromHex("#F7F7F7"),
Text = rightButtonText,
TextColor = Color.FromHex("#06A2D5"),
};
completionSource = new TaskCompletionSource<bool>();
rightButton.Clicked += (sender, e) =>
{
completionSource.SetResult(true);
ShowPopup = false;
};
mainLaout.Children.Add(rightButton, 2, 3, 2, 3);
}
// No buttons set here
if (completionSource == null)
{
completionSource = new TaskCompletionSource<bool>();
Task.Run(async () =>
{
await Task.Delay(3000);
completionSource.SetResult(true);
ShowPopup = false;
});
}
PopUpView = new ContentView
{
Padding = new Thickness(0),
VerticalOptions = LayoutOptions.CenterAndExpand,
Margin = new Thickness(5, 0),
Content = new Frame
{
Content = mainLaout,
IsClippedToBounds = true,
Padding = new Thickness(0),
BackgroundColor = Color.White
},
};
ShowPopup = true;
return completionSource.Task;
}
public void ShowLoading(string title = null)
{
var mainLayout = new StackLayout();
var indicator = new ActivityIndicator { IsRunning = true };
mainLayout.Children.Add(indicator);
if (!string.IsNullOrEmpty(title))
{
var label = new Label
{
Text = title,
HorizontalTextAlignment = TextAlignment.Center,
TextColor = Color.White
};
mainLayout.Children.Add(label);
}
PopUpView = new ContentView
{
Content = mainLayout,
VerticalOptions = LayoutOptions.CenterAndExpand,
BackgroundColor = Color.Transparent
};
ShowPopup = true; ;
}
public void HideAllPopup()
{
PopUpView = null;
ShowPopup = false;
}
}
}

view raw
BasePage.cs
hosted with ❤ by GitHub

<?xml version="1.0" encoding="UTF-8"?>
<local:BasePage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:{YOURNAMESPACE};assembly={YOURNAMESPACE}"
xmlns:fe="clr-namespace:FreshEssentials;assembly=FreshEssentials"
x:Class="Proofpoint.MessageListPage">
<local:BasePage.Header>
<ContentView BackgroundColor="{StaticResource GlobalBlue}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Source="Back.png"
fe:TappedGestureAttached.Command="{Binding GoBackCommand}"
HeightRequest="25" WidthRequest="25"
HorizontalOptions="Center" VerticalOptions="Center"/>
<Label Text="{Binding RightToolbarTitle}" Grid.ColumnSpan="2" HorizontalTextAlignment="End" Margin="14,0" Style="{StaticResource TitleWhite}" VerticalTextAlignment="Center"/>
</Grid>
</ContentView>
</local:BasePage.Header>
<local:BasePage.Footer>
<ContentView BackgroundColor="{StaticResource GlobalBlue}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="44" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="44" />
</Grid.ColumnDefinitions>
<Image Source="SortLeft.png" Margin="10,0" WidthRequest="30"
IsVisible="{Binding ShowLeftButton}"
HorizontalOptions="Start" fe:TappedGestureAttached.Command="{Binding LeftButtonCommand}" />
<Label Text="{Binding BottomTitle}" VerticalTextAlignment="Center" HorizontalTextAlignment="Center" Grid.Column="1" Style="{StaticResource TitleWhite}" />
<Image Source="SortRight.png" Margin="10,0" WidthRequest="30"
IsVisible="{Binding ShowRightButton}" Grid.Column="2"
HorizontalOptions="End" fe:TappedGestureAttached.Command="{Binding RightButtonCommand}" />
</Grid>
</ContentView>
</local:BasePage.Footer>
<local:BasePage.ContentPresenter>
<ContentView >
<ListView ItemsSource="{Binding ItemSource}" SelectedItem="{Binding SelectedItem}" >
<ListView.RowHeight>
<OnPlatform x:TypeArguments="x:Int32" iOS="76" Android="90" />
</ListView.RowHeight>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Padding="10" RowSpacing="10" ColumnSpacing="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="15" />
<ColumnDefinition Width="60" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label Text="{Binding Summary.Subject}" FontSize="16" TextColor="{Binding TitleTextColor}" LineBreakMode="TailTruncation" >
<Label.FontFamily>
<OnPlatform x:TypeArguments="x:String" iOS="SourceSansPro-Semibold" Android="SourceSansPro-Semibold.ttf#SourceSansPro-Semibold" />
</Label.FontFamily>
</Label>
<Image Source="Attachment.png" Grid.Column="1" IsVisible="{Binding Summary.HasAttachments}" />
<Label Text="{Binding SendDate}" FontSize="16" TextColor="#06A2D5" Grid.Column="2"/>
<Label Text="{Binding Sender}" TextColor="#7A7A7B" Grid.Row="1" Grid.ColumnSpan="3" />
<Label Text="{Binding To}" TextColor="#7A7A7B" Grid.Row="2" Grid.ColumnSpan="3" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentView>
</local:BasePage.ContentPresenter>
</local:BasePage>

view raw
Demo.xaml
hosted with ❤ by GitHub

Here are some demo images for that

Hope everybody can enjoy it.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s