UI freezes for 2-3 seconds when loading a carouselview - xamarin

I have a carouselview binded to a viewmodel, on the previous page (call it first page) user can select 2 arguments and with the help of those, the next view (call it second page) is generated accordingly. However, I can't wrap my head around why my view won't load asynchronously.
So my problem: When I click the button on the first page the UI would freeze for like a solid 2-3 seconds, and then start load (asynchronously?) and once it's done it's all good.
Also I couldn't really figure out a better way to inherit values from first page to second so if someone has an idea please let me know.
Any help on how can I fix this I would really appreciate.
The viewmodel for second page
public class DataSelectionViewModel : BaseViewModel
{
public ObservableCollection<Items> FilteredData { get; set; }
public UserSelectionViewModel()
{
_dataStore = DependencyService.Get<IDataStore>();
LoadData= new AsyncAwaitBestPractices.MVVM.AsyncCommand(FilterData);
FilteredData = new ObservableRangeCollection<Items>();
}
public async Task FilterData()
{
FilteredData.Clear();
var filtereddata = await _dataStore.SearchData(Hard, Subject).ConfigureAwait(false);
foreach (var data in filtereddata)
{
FilteredData.Add(data);
}
}
}
The carouselview in second page
<ContentPage.BindingContext>
<db:DataSelectionViewModel/>
</ContentPage.BindingContext>
...
<!-- DataTemplate for carouselview has radiobuttons, label and button all in a grid -->
<CarouselView ItemsSource="{Binding FilteredData}">
Second Page c#
public partial class SecondPage : ContentPage
{
public Coll(bool hard, string subject)
{
InitializeComponent();
var vm = (BaseViewModel)BindingContext;
vm.Hard = hard;
vm.Subject = subject;
/* had to set "hard" and "subject" here again, otherwise data won't load */
}
protected override async void OnAppearing()
{
var vm = (DataSelectionViewModel)BindingContext;
base.OnAppearing();
await vm.LoadData.ExecuteAsync().ConfigureAwait(false);
}
}
The first page view containing the button
<Button x:Name="Start" Pressed="ButtonClick"/>
First page c# --> Here I also tried doing it with a command and a pressed at the same time, because I couldn't come up with a way to save variables to second page viewmodel, that's why I use pressed here
private async void ButtonClick(object sender, EventArgs e)
{
var vm = (BaseViewModel)BindingContext;
vm.Hard = HardButtonSelected == Hard;
vm.Subject = vm.Subject.ToLower();
await Navigation.PushAsync(new SecondPage(vm.Hard, vm.Subject));
}
I have tried not using the OnAppearing method to get my data, but then it wouldn't bind to the page and it would not show, if I were to previously fill the ObservableCollection with my data and then load the page although I would love to be able to do this because it would allow me to create a loading popup also.

Related

How do I close all pages after changing an item's data?

I have a doubt in Xamarin forms, I have an application that I would like after finishing the training, it closes all the training screens and only the main screen remains, today I got a cod that does this, but when I restart the app and I login,
when he closes the screens instead of going back to the main screen he goes back to the login, I'm not using masterpage, could that be it?
source:
private async void BtnVoltar_Clicked(object sender, EventArgs e)
{
int numModals = Application.Current.MainPage.Navigation.ModalStack.Count;
// Pop each modal in the stack
for (int currModal = 0; currModal < numModals; currModal++)
{
await Application.Current.MainPage.Navigation.PopModalAsync();
}
await Navigation.PushModalAsync(new TabbedPageMenu());
}
Image Link
https://imgur.com/pOVVYBu
Another doubt would be after updating the data of an item, if it is possible to close the two screens and update it on the main screen
image link2
https://imgur.com/ZpevVNg
You can use the method to navigate to the different pages instead of close the pages.
The code in xaml you can add the command to do the navigation.
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type views:targetpagename}"
The code in xaml.cs or viewmodel
public ICommand NavigateCommand { get; private set; }
public MainPage()
{
InitializeComponent();
NavigateCommand = new Command<Type>(
async (Type pageType) =>
{
Page page = (Page)Activator.CreateInstance(pageType);
await Navigation.PushAsync(page);
});
BindingContext = this;
}

I tried to update a label in Xamarin.Forms, and it broke the entire app

I have a label on my app's main page that is supposed to update every fifteen seconds, but it only updates once and after that, a lot of things stop working. For example, if I try to open a new page after the label updates, the page's title is drawn in the same place as the back button (both of which are generated in the toolbar by Xamarin), and the page's content doesn't load at all. Also, I have a ListView on the page and if I try to select an item (which is supposed to open a new page) it only works the first time, after which point the ListView disappears, but the orange box that appears behind a selected item stays there.
How the label works at the moment is I have a timer in the App class that chooses a random piece of text from a list that I load in the app's OnStart() function (that part works properly) and then fires an event that is supposed to update the label.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Timers;
using System.Reflection;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using Partylist.Views;
using Partylist.Models;
namespace Partylist
{
public partial class App : Application, INotifyPropertyChanged
{
// Variable to store the currently selected event.
public static Event selectedEvent;
// Variable to store the currently selected list.
public static PartylistList selectedList;
// Struct to store information about tips.
public struct Tip
{
// A short version of the tip for the banner at the bottom of the screen.
public string Summary { get; set; }
// The full tip, which you can read by clicking the "More" button in the banner.
public string Full { get; set; }
}
// Array of tips.
public List<Tip> tips = new List<Tip>();
// Current tip.
public Tip CurrentTip { get; set; }
// Timer that gets the tip to update.
public Timer tipTimer = new Timer(15000);
// Random number generator for choosing the tip.
public Random rand = new Random();
// Event that tells the tip banners on the pages to update.
public static event EventHandler TipUpdate;
// Constructor.
public App()
{
// Do whatever initialization stuff this does.
InitializeComponent();
// Subscribes the timer's event handling function to its event.
tipTimer.Elapsed += OnTimerElapsed;
// Open the first page: the list of events.
MainPage = new NavigationPage(new EventsPage()) {
BarTextColor = Color.FromHex("FF4081")
};
}
// Loads tips data.
private void LoadTips()
{
// Variable for the assembly.
var assembly = IntrospectionExtensions.GetTypeInfo(typeof(App)).Assembly;
// Variable for the stream I use to read the text file.
Stream tipsStream = assembly.GetManifestResourceStream("Partylist.Resources.tips.txt");
// And a variable for the StreamReader.
StreamReader tipsReader = new StreamReader(tipsStream);
// Read the whole file into the list of tips.
while (!tipsReader.EndOfStream)
{
// Read a line into a "sumamry" variable.
string sum = tipsReader.ReadLine();
// Read another line into a "full" variable.
string full = tipsReader.ReadLine();
// Add an item to the list of tips that uses "summary" as the summary
// and "full" as the full tip.
tips.Add(new Tip()
{
Summary = sum,
Full = full
});
}
// Random index of the chosen tip.
int index = rand.Next(tips.Count);
// Set the current tip as the tip at that index.
CurrentTip = tips.ElementAt(index);
// Start timer (if it needs it).
tipTimer.Start();
}
// Event handling function for when the timer goes off.
private void OnTimerElapsed(object source, ElapsedEventArgs e)
{
// Random index of the chosen tip.
int index = rand.Next(tips.Count);
// Set the current tip as the tip at that index.
CurrentTip = tips.ElementAt(index);
// Fire the event to update the pages' tip banners.
TipUpdate?.Invoke(this, e);
}
// Standard lifecycle events.
protected override void OnStart()
{
// Call a function that loads the tips.
LoadTips();
}
protected override void OnSleep()
{
}
protected override void OnResume()
{
}
}
}
In the page's OnAppearing() method, I have the label's text set to the current tip (which at this point is null) and I subscribe the function that updates it to the event that the timer fires.
using Partylist.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace Partylist.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class EventsPage : ContentPage
{
// Text of the tip banner.
public string BannerText { get; set; }
// List of events, used to populate
// the page's ListView (see the XAML).
public ObservableCollection<Event> EventList { get; set; }
// Constructor.
public EventsPage()
{
// Does all the stuff to make the page
// exist that doesn't involve anything
// specific to this particular page in
// this particular app.
InitializeComponent();
// Set the label's BindingContext to the
// App class so it can update its text.
tipLabel.BindingContext = (App)App.Current;
}
// Runs when the page appears.
protected override void OnAppearing()
{
// Call the regular OnAppearing method.
base.OnAppearing();
// Set the BindingContext of the page to itself.
BindingContext = this;
// Update the ListView.
UpdateListView();
// Set the banner's text to the current tip's sumamry.
tipLabel.Text = ((App)App.Current).CurrentTip.Summary;
OnPropertyChanged("CurrentTip");
// Subscribe the OnTipUpdate function to the tipUpdate event in the app
// class.
App.TipUpdate += OnTipUpdate;
}
// Function to update the ListView whent he page loads or when something changes.
private void UpdateListView()
{
// Set the EventList to a new ObservableCollection
// which will be populated.
EventList = new ObservableCollection<Event>();
// Loop to populate the ObservableCollection.
for (int i = 0; i < Directory.GetDirectories(
Environment.GetFolderPath(
Environment.SpecialFolder
.LocalApplicationData))
.Length; i++)
{
// Add a new event.
EventList.Add(new Event()
{
// Set the folder name to the name of the folder
// that the even corresponds to.
FolderName = new DirectoryInfo(Directory.GetDirectories(
Environment.GetFolderPath(
Environment.SpecialFolder
.LocalApplicationData))[i]).Name,
// Sets the date/time created to the folder's
// creation date.
DateCreated = Directory
.GetCreationTime(Directory.GetDirectories(
Environment.GetFolderPath(
Environment.SpecialFolder
.LocalApplicationData))[i]),
// Sets the date/time last edited to the
// folder's write date.
DateEdited = Directory
.GetLastWriteTime(Directory.GetDirectories(
Environment.GetFolderPath(
Environment.SpecialFolder
.LocalApplicationData))[i])
});
// Set the ItemsSource of the ListView in the
// XAML to the ObservableCollection.
EventsListView.ItemsSource = EventList;
// Calls OnPropertyChanged() which makes the ListView update.
OnPropertyChanged("EventList");
}
}
// Function to go to the "New Event" page.
async void OnNewEventClicked(object sender, EventArgs e)
{
await Navigation.PushAsync(new NewEventPage());
}
// Function for when a ListView item is selected.
async void OnItemSelected(object sender, SelectedItemChangedEventArgs e)
{
App.selectedEvent = (Event)e.SelectedItem;
await Navigation.PushAsync(new ListsPage());
}
// Function to delete an event if the "Delete" context action is selected.
async void OnDelete(object sender, EventArgs e)
{
// Represents the thing to be deleted.
var del = (MenuItem)sender;
// Displays a confirmnation popup and stores the user's answer in a variable.
var answer = await DisplayAlert("Delete this event?",
"Are you sure you want to delete the event: \"" +
((Event)del.CommandParameter).FolderName + "\"?", "Delete", "Cancel");
// If the user accepted, delete the event with the MenuItem that ran this function.
if (answer)
{
Directory.Delete(Path.Combine(Environment.GetFolderPath(
Environment.SpecialFolder.LocalApplicationData),
((Event)del.CommandParameter).FolderName), true);
// Set the ItemsSource to null and back to make the ListView update.
EventsListView.ItemsSource = null;
UpdateListView();
}
}
// Function for when the current tip updates.
public void OnTipUpdate(object sender, EventArgs e)
{
// Make the label's text update.
tipLabel.Text = ((App)App.Current).CurrentTip.Summary;
OnPropertyChanged("CurrentTip");
}
}
}
Also, here is the page's XAML in case something is wrong with that.
<?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="Partylist.Views.EventsPage"
Title="Events"
BackgroundColor="White">
<ContentPage.ToolbarItems>
<ToolbarItem IconImageSource="settings_gear.png"
Priority="0"/>
</ContentPage.ToolbarItems>
<ContentPage.Content>
<!--Main layout of the page-->
<StackLayout>
<!--ListView of the events-->
<ListView x:Name="EventsListView"
ItemSelected="OnItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<!--These contewxt actions are buttons that appear
when you long press the item (Android) or swipe
left (iOS).-->
<ViewCell.ContextActions>
<MenuItem Clicked="OnDelete"
CommandParameter="{Binding .}"
Text="Delete"
IsDestructive="true"/>
</ViewCell.ContextActions>
<!--This is the content that actually appears-->
<StackLayout Padding="20,5">
<Label Text="{Binding FolderName}"
TextColor="#FF7700"
FontSize="Large"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<!--"New Event" button-->
<Button Text="+ Add New Event"
TextColor="#ff418b"
FontSize="Large"
BackgroundColor="#00ffffff"
Clicked="OnNewEventClicked"/>
<!--The banner at the bottom of the screen that gives tips-->
<Frame BorderColor="#ff418b"
Padding="0">
<FlexLayout Direction="Row"
AlignItems="Stretch"
JustifyContent="SpaceBetween">
<!--The "Tip" icon-->
<Image Source="tip_icon.png"
Margin="10"
FlexLayout.Basis="50"/>
<!--The short version of the tip-->
<Label x:Name="tipLabel"
VerticalTextAlignment="Center"
TextColor="#bb0099"
FontSize="Medium"
FontAttributes="Bold"
FlexLayout.Basis="250"/>
<!--The button that opens up a screen
with tyhe rest of the tip-->
<Button Text="More"
TextColor="White"
FontAttributes="Bold"
FontSize="Medium"
BackgroundColor="#ff418b"
FlexLayout.Basis="100"/>
</FlexLayout>
</Frame>
</StackLayout>
</ContentPage.Content>
</ContentPage>
What am I doing wrong and how do I keep my app from breaking when the label updates?
You need to update the text in Main thread:
Device.BeginInvokeOnMainThread (() => {
label.Text = "Async operation completed";
});
Refer: xamarin.forms.device.begininvokeonmainthread

How to hide navigation Toolbar icon in xamarin?

I want to hide navigation bar button in xamarin. how can i do that using binding. Toolbar item doesn't have "IsVisible" property.
Following is my xaml code
please help me to sort out this issue.
I would suggest to build a bindable ToolBoxItem. That way you can control the visibility through a view model property.
An implementation could look like that:
public class BindableToolbarItem : ToolbarItem
{
public static readonly BindableProperty IsVisibleProperty = BindableProperty.Create(nameof(IsVisible), typeof(bool), typeof(BindableToolbarItem), true, BindingMode.TwoWay, propertyChanged: OnIsVisibleChanged);
public bool IsVisible
{
get => (bool)GetValue(IsVisibleProperty);
set => SetValue(IsVisibleProperty, value);
}
private static void OnIsVisibleChanged(BindableObject bindable, object oldvalue, object newvalue)
{
var item = bindable as BindableToolbarItem;
if (item == null || item.Parent == null)
return;
var toolbarItems = ((ContentPage)item.Parent).ToolbarItems;
if ((bool)newvalue && !toolbarItems.Contains(item))
{
Device.BeginInvokeOnMainThread(() => { toolbarItems.Add(item); });
}
else if (!(bool)newvalue && toolbarItems.Contains(item))
{
Device.BeginInvokeOnMainThread(() => { toolbarItems.Remove(item); });
}
}
}
As you have discovered yourself there is not IsVisible. So you will have to implement functionality like that yourself if you still want it.
Another way would be to handle it in the pages' code-behind and remove or add the toolbar item whenever needed.
Adding and removing is simple, just add and remove items to the ToolbarItems collection: ToolbarItems.RemoveAt(0); for instance will remove the first toolbar item.
Putting #Gerald answer in action, it would be done this way:
void Done_Clicked(System.Object sender, System.EventArgs e)
{
//Do somthing and hide the done item
ShowDoneToolbarItem(false, (ToolbarItem)sender);
}
void Entry_Focused(System.Object sender, Xamarin.Forms.FocusEventArgs e)
{
//Show the done item
ShowDoneToolbarItem(true);
}
void ShowDoneToolbarItem(bool show, ToolbarItem item = null)
{
if(show)
{
ToolbarItem done = new ToolbarItem();
done.Text = "Done";
done.Clicked += Done_Clicked;
ToolbarItems.Add(done);
}
else if(item != null)
{
ToolbarItems.Remove(item);
}
}
This is cleaner and works from the code behind.
Well we need the IsVisible property for the front end, as xamarin doesn't have it, you can use Device.RuntimePlatform to check in real time which device the application is running. Since my code is in .cs of the XAML file, we can use xaml .cs to insert items into the screen.I put if () to do the logic and check if my device is on which platform, because I don't want it to display in UWP a toolbar.
The code is in .cs of the XAML file:
public kingTest()
{
InitializeComponent();
if((Device.RuntimePlatform == "Android")||(Device.RuntimePlatform == "iOS"))
{
ToolbarItem toolbar = new ToolbarItem();
toolbar.IconImageSource = "ic_ToolBar.png";
this.ToolbarItems.Add(toolbar);
}
};
I've achieved this easily using overloaded constructors. Here's an example:
View (add the name property):
<ContentPage x:Name="ContentPage"
<!-- rest of the tag -->
/>
Code-behind (add the toolbar items):
public partial class ExamplePage : ContentPage
{
public ExamplePage()
{
InitializeComponent();
BindingContext = this;
var saveToolbarItem = new ToolbarItem { Text = "Save" };
saveToolbarItem.Clicked += YourMethodToBeRan;
ContentPage.ToolbarItems.Add(saveToolbarItem);
}
public ExamplePage(Object object)
{
InitializeComponent();
BindingContext = this;
var updateToolbarItem = new ToolbarItem { Text = "Update" };
updateToolbarItem.Clicked += YourMethodToBeRan;
var deleteToolbarItem = new ToolbarItem { Text = "Delete" };
deleteToolbarItem.Clicked += YourMethodToBeRan;
ContentPage.ToolbarItems.Add(updateToolbarItem);
ContentPage.ToolbarItems.Add(deleteToolbarItem);
}
// rest of the class
}
The above pseudocode will add the "Save" toolbar item when the class is instantiated with no parameter, or the "Update" and "Delete" when a parameter is provided.
This isn't as elegant as IsEnabled / IsVisible booleans but it's a step in the right direction. Following this train of thought, you could modify the children of your toolbar during runtime to "show" and "hide" by adding and removing them as children.
Good luck!
I don't know if #tequila slammer's solution fully worked on Xamarin, but for us it only kind of works in .Net Maui (the evolution of Xamarin) and binding the IsVisible property to a variable.
Once the BindableToolbarItem is removed from the ContentPage's list of ToolbarItems, it is disconnected from the object that IsVisible is bound to forever.
For example: We want to use this control to hide or show a ToolbarItem that navigates to the admin screen, if I log in as the administrator on app launch, the item is there...great. If I then log out and log in as a non-admin, the item is not there...perfect. If I then log out and log in as an admin, the item is not there (the propertyChanged: OnIsVisibleChanged never fired)...:-(.
Not a big deal for us, if you want admin access then stopping the app and starting the app to log in as the admin is not a big ask.
In the newest release with .Net 7 the workaround works never more !
The reason is because the toolbar item which revomed will destoyed !

Xamarin Forms: how not reload ListView when pop back

In Xamarin Forms i have a ListView and the following method in Code Behind:
protected async override void OnAppearing()
{
base.OnAppearing();
events.ItemsSource = await App.ServiceManager.GetStream();
}
where
events
is my ListView and fetch data from rest webservice.
When i select an item in the ListView i push a detail page. The problem is that when i pop back to the ListView, the method OnAppearing() is called and make the remote call again.
Instead i'd like that the scroll start from the previous position (before that i push a new page): how can do that?
I think you can simply use a
bool isFirstAppearing = true;
protected async override void OnAppearing()
{
base.OnAppearing();
if(isFirstAppearing) {
isFirstAppearing = false;
events.ItemsSource = await App.ServiceManager.GetStream();
}
}
You can either do a check if its already been loaded, as alessandro Caliaros answer suggests, or an alternative if you want to get fresh data but still be scrolled in the same position, you can add code in onappearing to set the scroll position to be the same as it was before:
var currentYPosition = _scrollView.ScrollY;
await _scrollView.ScrollToAsync(_scrollView.ScrollX, currentYPosition, true);

Custom Popup in Xamarin.Forms

Is there any way to create custom popup dialog with Editor inside it using Xamarin Forms. Targeted to iOS platform.
I want a pop up with a Title Label ,Text box for accepting input and error Label for displaying error message, with OK and Cancel button.
I want to accept pin number from input pop up and have to validate pin. If validation fails I have to show a Error message inside pop up.
Thanks,
This is a good popup for XF that includes the ability to add an editor to the popup.
Popup Page Plugin for Xamarin Forms
// Use these methods in PopupNavigation globally or Navigation in your pages
// Open new PopupPage
Task PushAsync(PopupPage page, bool animate = true) // Navigation.PushPopupAsync
// Hide last PopupPage
Task PopAsync(bool animate = true) // Navigation.PopPopupAsync
// Hide all PopupPage with animations
Task PopAllAsync(bool animate = true) // Navigation.PopAllPopupAsync
// Remove one popup page in stack
Task RemovePageAsync(PopupPage page, bool animate = true) // Navigation.RemovePopupPageAsync
XAML POPUP PAGE
<?xml version="1.0" encoding="utf-8" ?>
<pages:PopupPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:pages="clr-namespace:Rg.Plugins.Popup.Pages;assembly=Rg.Plugins.Popup"
xmlns:animations="clr-namespace:Rg.Plugins.Popup.Animations;assembly=Rg.Plugins.Popup"
x:Class="Demo.Pages.MyPopupPage">
<!--Animations use example-->
<pages:PopupPage.Animation>
<animations:ScaleAnimation
PositionIn="Center"
PositionOut="Center"
ScaleIn="1.2"
ScaleOut="0.8"
DurationIn="400"
DurationOut="300"
EasingIn="SinOut"
EasingOut="SinIn"
HasBackgroundAnimation="True"/>
</pages:PopupPage.Animation>
<!-- Content -->
</pages:PopupPage>
POPUP PAGE
public partial class MyPopupPage : PopupPage
{
public SecondPopupPage()
{
InitializeComponent();
}
protected override void OnAppearing()
{
base.OnAppearing();
}
protected override void OnDisappearing()
{
base.OnDisappearing();
}
// Method for animation child in PopupPage
// Invoced after custom animation end
protected virtual Task OnAppearingAnimationEnd()
{
return Content.FadeTo(0.5);
}
// Method for animation child in PopupPage
// Invoked before custom animation begin
protected virtual Task OnDisappearingAnimationBegin()
{
return Content.FadeTo(1);;
}
protected override bool OnBackButtonPressed()
{
// Prevent hide popup
//return base.OnBackButtonPressed();
return true;
}
// Invoced when background is clicked
protected override bool OnBackgroundClicked()
{
// Return default value - CloseWhenBackgroundIsClicked
return base.OnBackgroundClicked();
}
}
MAINPAGE
// Main Page
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
// Button Click
private async void OnOpenPupup(object sender, EventArgs e)
{
var page = new MyPopupPage();
await Navigation.PushPopupAsync(page);
// or
await PopupNavigation.PushAsync(page);
}
}
Have a look at ACR User Dialogs. https://github.com/aritchie/userdialogs
Nuget Package: https://www.nuget.org/packages/Acr.UserDialogs/
Then have a look at the Prompt Examples: https://github.com/aritchie/userdialogs/blob/master/src/Samples/Samples/ViewModels/StandardViewModel.cs#L97
void Prompt()
{
UserDialogs.Instance.ActionSheet(new ActionSheetConfig()
.SetTitle("Choose Type")
.Add("Default", () => this.PromptCommand(InputType.Default))
.Add("E-Mail", () => this.PromptCommand(InputType.Email))
.Add("Name", () => this.PromptCommand(InputType.Name))
.Add("Number", () => this.PromptCommand(InputType.Number))
.Add("Number with Decimal", () => this.PromptCommand(InputType.DecimalNumber))
.Add("Password", () => this.PromptCommand(InputType.Password))
.Add("Numeric Password (PIN)", () => this.PromptCommand(InputType.NumericPassword))
.Add("Phone", () => this.PromptCommand(InputType.Phone))
.Add("Url", () => this.PromptCommand(InputType.Url))
);
}
Yes, a custom popup can be added in Xamarin forms. Please follow these steps:
Create one stacklayout.
Add the fields in to the stacklayout.
Create one new Frame object.
Make the Frame object background with transaprent color.
Add the Stacklayout object into frame.
Add the frame to main content page.
If you need code, I will update.

Resources