Floating Action Button in Xamarin.Forms - android

I had completed my App's home page in Xamarin.Forms Portable.
Now i want to add a Flotation Action Button In my Android Project !
Is there any way to add FAB for Android in my existing home page, which was coded in Xamarin.Forms Portable.
OR
I want to create a separate home page for Android and add call it as a MainPage for android ?
Thanks and Regards.

Before the official support library came out I ported the FAB over.
There is now a Xamarin.Forms sample in my GitHub repo that you can use: https://github.com/jamesmontemagno/FloatingActionButton-for-Xamarin.Android

Build a Custom Control
For the FAB's properties to be bindable in Xamarin.Forms, we need a custom control with bindable properties.
public class FloatingActionButtonView : View
{
public static readonly BindableProperty ImageNameProperty = BindableProperty.Create<FloatingActionButtonView,string>( p => p.ImageName, string.Empty);
public string ImageName
{
get { return (string)GetValue (ImageNameProperty); }
set { SetValue (ImageNameProperty, value); }
}
public static readonly BindableProperty ColorNormalProperty = BindableProperty.Create<FloatingActionButtonView,Color>( p => p.ColorNormal, Color.White);
public Color ColorNormal
{
get { return (Color)GetValue (ColorNormalProperty); }
set { SetValue (ColorNormalProperty, value); }
}
public static readonly BindableProperty ColorPressedProperty = BindableProperty.Create<FloatingActionButtonView,Color>( p => p.ColorPressed, Color.White);
public Color ColorPressed
{
get { return (Color)GetValue (ColorPressedProperty); }
set { SetValue (ColorPressedProperty, value); }
}
public static readonly BindableProperty ColorRippleProperty = BindableProperty.Create<FloatingActionButtonView,Color>( p => p.ColorRipple, Color.White);
public Color ColorRipple
{
get { return (Color)GetValue (ColorRippleProperty); }
set { SetValue (ColorRippleProperty, value); }
}
...
}
We will then map each property to a corresponding property on the native FAB control.
Attach a Renderer
If we want to use a native control in Xamarin.Forms, we need a renderer. For simplicity, lets use a ViewRenderer. This renderer will map our custom FloatingActionButtonView to an Android.Widget.FrameLayout.
public class FloatingActionButtonViewRenderer : ViewRenderer<FloatingActionButtonView, FrameLayout>
{
...
private readonly Android.Content.Context context;
private readonly FloatingActionButton fab;
public FloatingActionButtonViewRenderer()
{
context = Xamarin.Forms.Forms.Context;
fab = new FloatingActionButton(context);
...
}
protected override void OnElementChanged(ElementChangedEventArgs<FloatingActionButtonView> e)
{
base.OnElementChanged(e);
if (e.OldElement != null || this.Element == null)
return;
if (e.OldElement != null)
e.OldElement.PropertyChanged -= HandlePropertyChanged;
if (this.Element != null) {
//UpdateContent ();
this.Element.PropertyChanged += HandlePropertyChanged;
}
Element.Show = Show;
Element.Hide = Hide;
SetFabImage(Element.ImageName);
fab.ColorNormal = Element.ColorNormal.ToAndroid();
fab.ColorPressed = Element.ColorPressed.ToAndroid();
fab.ColorRipple = Element.ColorRipple.ToAndroid();
var frame = new FrameLayout(Forms.Context);
frame.RemoveAllViews();
frame.AddView(fab);
SetNativeControl (frame);
}
public void Show(bool animate = true)
{
fab.Show(animate);
}
public void Hide(bool animate = true)
{
fab.Hide(animate);
}
void HandlePropertyChanged (object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == "Content") {
Tracker.UpdateLayout ();
}
else if (e.PropertyName == FloatingActionButtonView.ColorNormalProperty.PropertyName)
{
fab.ColorNormal = Element.ColorNormal.ToAndroid();
}
else if (e.PropertyName == FloatingActionButtonView.ColorPressedProperty.PropertyName)
{
fab.ColorPressed = Element.ColorPressed.ToAndroid();
}
else if (e.PropertyName == FloatingActionButtonView.ColorRippleProperty.PropertyName)
{
fab.ColorRipple = Element.ColorRipple.ToAndroid();
}
...
}
void SetFabImage(string imageName)
{
if(!string.IsNullOrWhiteSpace(imageName))
{
try
{
var drawableNameWithoutExtension = Path.GetFileNameWithoutExtension(imageName);
var resources = context.Resources;
var imageResourceName = resources.GetIdentifier(drawableNameWithoutExtension, "drawable", context.PackageName);
fab.SetImageBitmap(Android.Graphics.BitmapFactory.DecodeResource(context.Resources, imageResourceName));
}
catch(Exception ex)
{
throw new FileNotFoundException("There was no Android Drawable by that name.", ex);
}
}
}
}
Pull it all Together
OK! We've built the custom control, and mapped it to a renderer. The last step is laying out the control in our view.
public class MainPage : ContentPage
{
public MainPage()
{
var fab = new FloatingActionButtonView() {
ImageName = "ic_add.png",
ColorNormal = Color.FromHex("ff3498db"),
ColorPressed = Color.Black,
ColorRipple = Color.FromHex("ff3498db")
};
// Main page layout
var pageLayout = new StackLayout {
Children =
{
new Label {
VerticalOptions = LayoutOptions.CenterAndExpand,
XAlign = TextAlignment.Center,
Text = "Welcome to Xamarin Forms!"
}
}};
var absolute = new AbsoluteLayout() {
VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand };
// Position the pageLayout to fill the entire screen.
// Manage positioning of child elements on the page by editing the pageLayout.
AbsoluteLayout.SetLayoutFlags(pageLayout, AbsoluteLayoutFlags.All);
AbsoluteLayout.SetLayoutBounds(pageLayout, new Rectangle(0f, 0f, 1f, 1f));
absolute.Children.Add(pageLayout);
// Overlay the FAB in the bottom-right corner
AbsoluteLayout.SetLayoutFlags(fab, AbsoluteLayoutFlags.PositionProportional);
AbsoluteLayout.SetLayoutBounds(fab, new Rectangle(1f, 1f, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize));
absolute.Children.Add(fab);
Content = absolute;
}
}
Complete code on Github : Floating Action Button Xamarin.Forms

Related

Xamarin - Hide Cancel button or change it for Ok on Custom Picker

I have a Xamarin Forms project on visual studio 2019.
I wanted to hide the cancel button from a simple Picker but wasn't able to do so, so I have now a custom picker but don't know how to remove that button. Either that or changing the "Cancel" button for an "Ok" would be what I want.
The thing is the examples that I have seen are customizing this by using the NumberPicker class and this won't work for me as I don't want to display my list that way.
My CustomPicker class
public class CustomPicker : Picker
{
public static readonly BindableProperty ImageProperty =
BindableProperty.Create(nameof(Image), typeof(string), typeof(CustomPicker), string.Empty);
public string Image
{
get { return (string)GetValue(ImageProperty); }
set { SetValue(ImageProperty, value); }
}
}
My CustomPickerRenderer class on Android project
public class CustomPickerRenderer : Xamarin.Forms.Platform.Android.AppCompat.PickerRenderer
{
public CustomPickerRenderer(Context context) : base(context) { }
CustomPicker element;
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
{
base.OnElementChanged(e);
element = (CustomPicker)this.Element;
if (Control != null && this.Element != null && !string.IsNullOrEmpty(element.Image))
{
Control.Background = AddPickerStyles(element.Image);
Control.Gravity = GravityFlags.CenterHorizontal;
}
}
public LayerDrawable AddPickerStyles(string imagePath)
{
ShapeDrawable border = new ShapeDrawable();
border.Paint.Color = Android.Graphics.Color.Gray;
border.SetPadding(10, 10, 10, 10);
border.Paint.SetStyle(Paint.Style.Stroke);
Drawable[] layers = { border, GetDrawable(imagePath) };
LayerDrawable layerDrawable = new LayerDrawable(layers);
layerDrawable.SetLayerInset(0, 0, 0, 0, 0);
return layerDrawable;
}
private BitmapDrawable GetDrawable(string imagePath)
{
int resID = Resources.GetIdentifier(imagePath, "drawable", this.Context.PackageName);
var drawable = ContextCompat.GetDrawable(this.Context, resID);
var bitmap = ((BitmapDrawable)drawable).Bitmap;
var result = new BitmapDrawable(Resources, Bitmap.CreateScaledBitmap(bitmap, 70, 70, true));
result.Gravity = Android.Views.GravityFlags.Right;
return result;
}
}
My CustomPickerRenderer on iOS project
public class CustomPickerRenderer : PickerRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
{
base.OnElementChanged(e);
var element = (CustomPicker)this.Element;
if (this.Control != null && this.Element != null && !string.IsNullOrEmpty(element.Image))
{
var downarrow = UIImage.FromBundle(element.Image);
Control.RightViewMode = UITextFieldViewMode.Always;
Control.RightView = new UIImageView(downarrow);
Control.TextAlignment = UITextAlignment.Center;
}
}
}
How can I achieve this? Please help and thanks.
You can set a donetextproperty in your picker and set it in the uibuttontext on ios side.like:
public class MyPicker:Picker
{
public static readonly BindableProperty DonebuttonTextProperty = BindableProperty.Create("DonebuttonText", typeof(string),
typeof(string), null);
public string DonebuttonText { get { return (string)GetValue(DonebuttonTextProperty); }
set { SetValue(DonebuttonTextProperty, value); }
}
public MyPicker()
{
}
}
}
iOSRenderer:
public class MyPickerRenderer:PickerRenderer
{
public MyPickerRenderer()
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
{
base.OnElementChanged(e);
if (e.NewElement == null) return;
var customPicker = e.NewElement as MyPicker;
if (Control == null)
{
SetNativeControl(new UITextField
{
RightViewMode = UITextFieldViewMode.Always,
ClearButtonMode = UITextFieldViewMode.WhileEditing
});
SetUIbutton(customPicker.DonebuttonText);
}
else
{ SetUIbutton(customPicker.DonebuttonText); }
}
public void SetUIbutton(string doneButtonText)
{
UIToolbar toolbar = new UIToolbar();
toolbar.BarStyle = UIBarStyle.Default;
toolbar.Translucent = true;
toolbar.SizeToFit();
UIBarButtonItem doneButton = new UIBarButtonItem(string.IsNullOrEmpty(doneButtonText) ? "OK" : doneButtonText,
UIBarButtonItemStyle.Done, (s, ev) => { Control.ResignFirstResponder(); });
UIBarButtonItem flexible = new UIBarButtonItem(UIBarButtonSystemItem.FlexibleSpace);
toolbar.SetItems(new UIBarButtonItem[] { doneButton, flexible }, true);
Control.InputAccessoryView = toolbar;
}
}
As for android, change text in NegativeButton like:
public class MyPickerRenderer : PickerRenderer
{
public MyPickerRenderer(Context context) : base(context)
{
}
private IElementController ElementController => Element as IElementController;
private AlertDialog _dialog;
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
{
base.OnElementChanged(e);
if (e.NewElement == null || e.OldElement != null)
return;
Control.Click += Control_Click;
}
protected override void Dispose(bool disposing)
{
Control.Click -= Control_Click;
base.Dispose(disposing);
}
private void Control_Click(object sender, EventArgs e)
{
Picker model = Element;
var picker = new NumberPicker(Context);
if (model.Items != null && model.Items.Any())
{
picker.MaxValue = model.Items.Count - 1;
picker.MinValue = 0;
picker.SetDisplayedValues(model.Items.ToArray());
picker.WrapSelectorWheel = false;
picker.DescendantFocusability = DescendantFocusability.BlockDescendants;
picker.Value = model.SelectedIndex;
}
var layout = new LinearLayout(Context) { Orientation = Orientation.Vertical };
layout.AddView(picker);
ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, true);
var builder = new AlertDialog.Builder(Context);
builder.SetView(layout);
builder.SetTitle(model.Title ?? "");
builder.SetNegativeButton("OK ", (s, a) =>
{
ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
// It is possible for the Content of the Page to be changed when Focus is changed.
// In this case, we'll lose our Control.
Control?.ClearFocus();
_dialog = null;
});
builder.SetPositiveButton("Done", (s, a) =>
{
ElementController.SetValueFromRenderer(Picker.SelectedIndexProperty, picker.Value);
// It is possible for the Content of the Page to be changed on SelectedIndexChanged.
// In this case, the Element & Control will no longer exist.
if (Element != null)
{
if (model.Items.Count > 0 && Element.SelectedIndex >= 0)
Control.Text = model.Items[Element.SelectedIndex];
ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
// It is also possible for the Content of the Page to be changed when Focus is changed.
// In this case, we'll lose our Control.
Control?.ClearFocus();
}
_dialog = null;
});
_dialog = builder.Create();
_dialog.DismissEvent += (ssender, args) =>
{
ElementController?.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
};
_dialog.Show();
}
}
}

Xamarin.Forms Imagesource issue

I have a view with an image: <Image Source="{Binding MainUrl}"/>
Image binding value : My image source on loading from database
the value of MainUrl variable is stored in an sqlite table.public string LogoUrl { get; set; }
viewmodel :
private string _logoUrl;
public string LogoUrl
{
get { return _logoUrl; }
set
{
SetValue(ref _logoUrl, value);
OnPropertyChanged(nameof(LogoUrl));
}
}
the user has the option to change the image using filepicker :
var file = await FilePicker.PickAsync(options);
if (file == null)
{
return;
}
var stream = await file.OpenReadAsync();
MainUrl = ImageSource.FromStream(() => stream);
LblImportLogo = file.FullPath;
Parameter.LogoUrl = file.FullPath;
when I choose an image with filepicker, this one is well displayed and the the path is saved into sqlite table but when I restart the application, the image is no longer displayed despite the path being well informed (this one is external). the problem is in all platforms, UWP,android and IOS. can you help me find a solution.
Mainpage.xaml.cs :
public MainPage()
{
var parameterStore = new SQLiteParameterStore(DependencyService.Get<ISQLiteDb>());
var pageService = new PageService();
ViewModel = new MainPageViewModel(parameterStore, pageService);
InitializeComponent();
NavigationPage.SetHasBackButton(this, false);
NavigationPage.SetHasNavigationBar(this, false);
}
protected override void OnAppearing()
{
ViewModel.LoadDataCommand.Execute(null);
base.OnAppearing();
}
public MainPageViewModel ViewModel
{
get { return BindingContext as MainPageViewModel; }
set { BindingContext = value; }
}
MainPageViewModel :
......
private ImageSource _mainurl;
public ImageSource MainUrl
{
get { return _mainurl; }
set
{
SetValue(ref _mainurl, value);
OnPropertyChanged(nameof(MainUrl));
}
}
......
private async Task LoadData()
{
var parameters = await _parameterStore.GetAll();
var elts = parameters.Count();
if (elts < 1)
{
//set default values
mainParameter = new Parameter();
mainParameter.LogoUrl = "default.jpg";
MainUrl = mainParameter.LogoUrl;
}
else
{
//set parameters
mainParameter = parameters[0];
MainUrl = ImageSource.FromFile(mainParameter.LogoUrl);
}
}

Custom renderer for Tabbed page in Android: Xamarin Forms

I am working on a Xamarin.Forms application. I have this tabbed page renderer in iOS:
public class TabbedPageRenderer : TabbedRenderer
{
private MainPage _page;
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
_page = (MainPage)e.NewElement;
}
else
{
_page = (MainPage)e.OldElement;
}
try
{
var tabbarController = (UITabBarController)this.ViewController;
if (null != tabbarController)
{
tabbarController.ViewControllerSelected += OnTabBarReselected;
}
}
catch (Exception exception)
{
Console.WriteLine(exception);
}
}
private void OnTabBarReselected(object sender, UITabBarSelectionEventArgs e)
{
var tabs = Element as TabbedPage;
var playTab = tabs.Children[4];
if (TabBar.SelectedItem.Title == "Play")
{
if (tabs != null)
{
playTab.Title = "Pause";
playTab.Icon = "pause.png";
}
App.pauseCard = false;
}
else
{
if (tabs != null)
{
playTab.Title = "Play";
playTab.Icon = "play.png";
}
App.pauseCard = true;
}
}
}
This basically changes the icon on my Play tab to pause and play. This is working good in iOS. But I am struggling on how to have the same function (basically convert this to Android) in Android side.
Can any point me to the right direction? Basically help me? :-)
Note: I am pretty new with Android development.
EDIT: This is what it would look like in iOS.
Pause Mode:
Play Mode:
There is a blog post by Xamarin's James Montemagno which explains how to achieve this requirement.
Basically, it uses Custom Tab which inherits from TabbedPage which initialize an event UpdateIcons to be fired on Tab Current Page Changed event CurrentPageChanged
public class MyTabs : TabbedPage
{
//always save a reference to the current page
Page currentPage;
public MyTabs()
{
//create the pages and set the view models
//you could also do this in the page code behind
Children.Add(new TabIconsPage
{
BindingContext = new Tab1ViewModel
{
IsSelected = true
}
});
Children.Add(new TabIconsPage2
{
BindingContext = new Tab2ViewModel()
});
currentPage = Children[0];
//Register for page changes
this.CurrentPageChanged += Handle_CurrentPageChanged;
}
//Update the IsSelected state and trigger an Event that anyone can loop into.
public event EventHandler UpdateIcons;
void Handle_CurrentPageChanged(object sender, EventArgs e)
{
var currentBinding = currentPage.BindingContext as IIconChange;
if (currentBinding != null)
currentBinding.IsSelected = false;
currentPage = CurrentPage;
currentBinding = currentPage.BindingContext as IIconChange;
if (currentBinding != null)
currentBinding.IsSelected = true;
UpdateIcons?.Invoke(this, EventArgs.Empty);
}
}
Now Android needs a custom renderer to subscribe to the UpdateIcons event and perform icon changes
public class MyTabs : TabbedPage
{
//always save a reference to the current page
Page currentPage;
public MyTabs()
{
//create the pages and set the view models
//you could also do this in the page code behind
Children.Add(new TabIconsPage
{
BindingContext = new Tab1ViewModel
{
IsSelected = true
}
});
Children.Add(new TabIconsPage2
{
BindingContext = new Tab2ViewModel()
});
currentPage = Children[0];
//Register for page changes
this.CurrentPageChanged += Handle_CurrentPageChanged;
}
//Update the IsSelected state and trigger an Event that anyone can loop into.
public event EventHandler UpdateIcons;
void Handle_CurrentPageChanged(object sender, EventArgs e)
{
var currentBinding = currentPage.BindingContext as IIconChange;
if (currentBinding != null)
currentBinding.IsSelected = false;
currentPage = CurrentPage;
currentBinding = currentPage.BindingContext as IIconChange;
if (currentBinding != null)
currentBinding.IsSelected = true;
UpdateIcons?.Invoke(this, EventArgs.Empty);
}
}

OnElementChanged(...) not getting the new value of property

I have a a map that displays a route between points. This is working but now I want to pass some color values from PCL. I have a custom renderer for android and a class acting as bridge between PCL and android with bindable properties in it.
(For the map I use the PCL implementation and extends it with the custom renderer)
For now I got:
(android : CustomMapRenderer)
[assembly: ExportRenderer(typeof(CustomMap), typeof(MapOverlay.Droid.CustomMapRenderer))]
namespace MapOverlay.Droid
{
public class CustomMapRenderer : MapRenderer , ICustomMap
{
List<Position> routeCoordinates;
Int32 RouteColor;
protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Map> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
// Unsubscribe
}
if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
routeCoordinates = formsMap.RouteCoordinates;
Control.GetMapAsync(this);
}
}
protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (this.Element == null || this.Control == null)
return;
if (e.PropertyName == "VisibleRegion")
{
var polylineOptions = new PolylineOptions();
polylineOptions.InvokeColor(0x66FF0000);
foreach (var position in routeCoordinates)
{
polylineOptions.Add(new LatLng(position.Latitude, position.Longitude));
}
NativeMap.AddPolyline(polylineOptions);
}
}
public void working()
{
Log.Debug("xxxx", "WORKING");
}
}
}
Now the class acting as bridge from PCL to Android
(PCL : CustomMap)
namespace SomeNamespace
{
public class CustomMap : Map
{
public static readonly BindableProperty RouteCoordinatesProperty =
BindableProperty.Create<CustomMap, List<Position>>(p => p.RouteCoordinates, new List<Position>());
public static readonly BindableProperty RouteColorProperty =
BindableProperty.Create<CustomMap, int>(p => p.RouteColor, 0x66FF0000);
//Property used to add points to the map. Then polyline utility will draw a line beteween thoses points
public List<Position> RouteCoordinates
{
get { return (List<Position>)base.GetValue(RouteCoordinatesProperty); }
set {
base.SetValue(RouteCoordinatesProperty, value);
}
}
public Int32 RouteColor
{
get { return (Int32)base.GetValue(RouteColorProperty); }
set { base.SetValue(RouteColorProperty, value); }
}
public CustomMap()
{
RouteCoordinates = new List<Position>();
}
}
}
So as you can see I added an Int32 RouteColor variable wich should be used in the CustomMapRenderer to change the color of the displayed route.
But when I change this value in my PCL code like so :
mCustomMap.RouteColor = 0x22AA0000;
It triggers an OnElementPropertyChanged response but not an OnElementChanged event.
So I can't get the changed value. I only know that it DID changed (with the OnElementPropertyChanged).
If someone knows how to bypass this phenomena... All suggestions are welcome ;-)
Thanks in advance !
Element represents the forms element, which in this case should be CustomMap. You can use it to retrieve the property values.
For e.g.:
protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (this.Element == null || this.Control == null)
return;
....
//if RouteColor is the property that changed
if (e.PropertyName == nameof(CustomMap.RouteColor))
{
//get new value
var newColor = (Element as CustomMap)?.RouteColor;
//and, update native control
....

Android only allows one navigation page - Xamarin Forms

Hi I created the application using Xamarin.Forms - Its working fine in iOS but Certainly Its not working in Android and facing some issues mentioned in the title.
Lemme explain my application and code continues, The application having one login screen and will move on to home screen called HomeController using navigation in this just populating list view and its cell. While tapping each row will move on to Master detail page in this I'm getting error and it's working fine in iOS not Android.
App.cs
using System;
using Xamarin.Forms;
namespace eMO_Xamarin
{
public class App : Application
{
public App ()
{
// The root page of your application
var nav = new NavigationPage (new LoginViewController ());
nav.BarBackgroundColor = Color.FromHex("#EEEEEE");
nav.BarTextColor = Color.FromHex("#424242");
MainPage = nav;
}
}
}
LoginController.cs
using System;
using Xamarin.Forms;
using System.Collections.Generic;
namespace eMO_Xamarin
{
public class LoginViewController : ContentPage
{
Entry userEntry, passwordEntry;
public LoginViewController ()
{
NavigationPage.SetBackButtonTitle (this, "");
NavigationPage.SetHasBackButton (this, false);
this.BackgroundImage = "Bg1.jpg";
userEntry = new Entry () {
HorizontalOptions = LayoutOptions.FillAndExpand,
Placeholder = "Username"
};
passwordEntry = new Entry () {
HorizontalOptions = LayoutOptions.FillAndExpand,
Placeholder = "Password",
IsPassword = true
};
var loginButton = new Button () {
Text = "Login",
TextColor = Color.White,
BackgroundColor = Color.FromHex ("77D065")
};
loginButton.Clicked += OnButtonClickedLogin;
Title = "e-Loan";
this.Padding = new Thickness (50, Device.OnPlatform (20, 0, 0), 50, 20);
stack.Children.Add (appLogoImg);
stack.Children.Add (userEntry);
stack.Children.Add (passwordEntry);
stack.Children.Add (loginButton);
this.Content = scroll;
}
void OnButtonClickedLogin (object sender, EventArgs e)
{
Navigation.InsertPageBefore (new HomeViewController (), this);
Navigation.PopAsync ();
}
}
}
HomeController.cs
using System;
using System.Collections.Generic;
using Xamarin.Forms;
namespace eMO_Xamarin
{
public class HomeViewController : ContentPage
{
public HomeViewController ()
{
Title = "Welcome John!";
NavigationPage.SetBackButtonTitle (this, "Back");
NavigationPage.SetHasBackButton (this, false);
if (Device.Idiom == TargetIdiom.Phone) {
this.BackgroundImage = "login_home.jpg";
} else if (Device.Idiom == TargetIdiom.Tablet) {
this.BackgroundImage = "Bg6.jpg";
} else {
}
var toolbarItem = new ToolbarItem {
Text = "Logout"
};
toolbarItem.Clicked += OnLogoutButtonClicked;
ToolbarItems.Add (toolbarItem);
Label header = new Label {
Text = "Submitted Loans",
TextColor = Color.Gray,
FontAttributes = FontAttributes.Bold,
FontSize = 30,
HorizontalOptions = LayoutOptions.Center
};
// Create a data template from the type ImageCell
var cell = new DataTemplate (typeof(MenuCell));
ListView listView = new ListView {
ItemsSource = VetData.GetData (),
ItemTemplate = cell, // Set the ImageCell to the item template for the listview
//SeparatorColor = Color.Transparent
};
listView.RowHeight = 75;
listView.BackgroundColor = Color.Transparent;
// Push the list view down below the status bar on iOS.
if (Device.Idiom == TargetIdiom.Phone) {
Padding = new Thickness (10, Device.OnPlatform (20, 0, 0), 0, 0);
} else if (Device.Idiom == TargetIdiom.Tablet) {
Padding = new Thickness (150, Device.OnPlatform (50, 0, 0), 150, 10);
} else {
}
// Set the content for the page.
this.Content = new StackLayout {
Spacing = 20,
Children = {
header,
listView
}
};
listView.ItemSelected += async (sender, e) => {
if (e.SelectedItem != null) {
//do what you want with the selectedItem
// Navigation with back push
await Navigation.PushAsync (new LeadViewController ());
}
//then init the selectedItem of the listview to enable it to be selected again
listView.SelectedItem = null;
};
}
async void OnLogoutButtonClicked (object sender, EventArgs e)
{
// Navigation with out back push
Navigation.InsertPageBefore (new LoginViewController (), this);
await Navigation.PopAsync ();
}
}
}
LeadViewController.cs : MasterDetailScreen : Error facing Screen
using System;
using System.Collections.Generic;
using Xamarin.Forms;
namespace eMO_Xamarin
{
public class LeadViewController : MasterDetailPage
{
public LeadViewController ()
{
this.BackgroundImage = "Bg6.jpg";
var menuPage = new MenuPage ();
menuPage.OnMenuSelect = (categoryPage) => {
Detail = new NavigationPage (categoryPage);
if (Device.Idiom == TargetIdiom.Phone) {
IsPresented = false;
} else if (Device.Idiom == TargetIdiom.Tablet) {
IsPresented = true;
} else {
IsPresented = true;
}
};
Master = menuPage;
Detail = new NavigationPage (new LetsGetStartedPage ());
MasterBehavior = MasterBehavior.Default;
}
}
}
Your root page is Navigation Page. And you added a MasterDetial Page with Navigation page too.
The similar issue here
Either MasterDetail or Navigation should be the root and not have them inside each other. You can't have 2 navigation pages within each othe
You can have a navigation page as the Detail in a MasterDetail or you can have MasterDetail inside a Navigation Page, but you can't have a navigation page inside a navigation page at any level. This is an Android only restriction but makes it a Xamarin Forms restriction in the end.
Here is your error code:
Detail = new NavigationPage (new LetsGetStartedPage ());
I think you can try the following code:
Detail = new LetsGetStartedPage ();
OR
namespace eMO_Xamarin
{
public class App : Application
{
public App ()
{
var nav = new LoginViewController ();
nav.BarBackgroundColor = Color.FromHex("#EEEEEE");
nav.BarTextColor = Color.FromHex("#424242");
MainPage = nav;
}
}
}
try this code :
listView.ItemSelected += async (sender, e) => {
if (e.SelectedItem != null) {
//do what you want with the selectedItem
// Navigation with back push
await Navigation.PushAsync (new NavigationPage(new LeadViewController ()));
}
//then init the selectedItem of the listview to enable it to be selected again
listView.SelectedItem = null;
};
please make sure that your App.cs has only setting page like this
MainPage = new MasterTestPage();
do not set like this
new NavigationPage(new MasterTestPage());
where MasterTestPage is my MasterDetailPage class

Categories

Resources