In my Xamarin app, on PIN Page, there are 8 Entry Fields, 4 for PIN and 4 for Confirm PIN (here I just paste 2).
When user enter a value in a field, the cursor focus on the next field and so on. But if they enter value mistakenly and wants to clear it, they can't go back to the last entry by pressing Backspace Button. They have to press on that entry field for focus.
Below is the Code for Entry Fields. How can I go back / focus on the last entry field by pressing Backspace button?
.xml
<Entry
x:Name="PasswordOne"
Text="{Binding PasswordOne}"
IsPassword="True"
Keyboard="Numeric"
MaxLength="1"
ReturnType="Next"
TextChanged="Entry_FieldChanged" />
.xml.cs
public PasswordPage()
{
InitializeComponent();
entryList = new List<Entry>();
entryList.Add(PasswordOne);
entryList.Add(PasswordTwo);
entryList.Add(ConfirmPasswordOne);
entryList.Add(ConfirmPasswordTwo);
}
private void Entry_FieldChanged(object sender, TextChangedEventArgs e)
{
var entry = sender as Entry;
const string numregex = "^[0-9]+$";
if (!(!System.Text.RegularExpressions.Regex.IsMatch(entry.Text, numregex) || entry.Text == ""))
{
if (entry.Text.Length >= 1)
{
var index = entryList.IndexOf(entry);
var nextIndex = (index + 1) >= entryList.Count ? 0 : index + 1;
var next = entryList.ElementAt(nextIndex);
if (entry == ConfirmPasswordTwo)
{ }
else
{
next?.Focus();
}
}
}
else
{
var index = entryList.IndexOf(entry);
var prevIndex = (index) == 0 ? 0 : index - 1;
var prev = entryList.ElementAt(prevIndex);
if (entry == PasswordOne)
{ }
else
{
prev?.Focus();
}
}
}
UPDATE
CustomEntry.xml.cs
namespace Mobile.App
{
public class CustomEntry : Entry
{
public delegate void BackspaceEventHandler(object sender, EventArgs e);
public event BackspaceEventHandler OnBackspace;
public CustomEntry() { }
public void OnBackspacePressed()
{
OnBackspace?.Invoke(null, null);
}
}
}
CustomEntryRenderer
[assembly: ExportRenderer(typeof(CustomEntry), typeof(CustomEntryRenderer))]
namespace Mobile.App.Droid
{
public class CustomEntryRenderer : EntryRenderer, IInputFilter
{
public CustomEntryRenderer(Context context) : base(context)
{
}
public ICharSequence FilterFormatted(ICharSequence source, int start, int end, ISpanned dest, int dstart, int dend)
{
if (string.IsNullOrWhiteSpace(source.ToString()))
{
var entry = (CustomEntry)Element;
entry.OnBackspacePressed();
}
return source;
}
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (Control == null)
{
return;
}
if (Control != null)
{
int length = Control.Text.Length;
Control.SetSelection(length);
SetColors();
};
Control.SetFilters(new IInputFilter[] { this });
}
private void SetColors()
{
Control.SetBackgroundColor(Android.Graphics.Color.Transparent);
}
}
}
.xml.cs
public partial class PasswordPage : ContentPage
{
public List<Entry> entryList { get; set; }
public PasswordPage()
{
InitializeComponent();
ValidatePassword();
entryList = new List<Entry>();
entryList.Add(PasswordOne);
entryList.Add(PasswordTwo);
entryList.Add(ConfirmPasswordOne);
entryList.Add(ConfirmPasswordTwo);
}
Entry entry;
private void Entry_FieldChanged(object sender, TextChangedEventArgs e)
{
entry = sender as Entry;
const string numregex = "^[0-9]+$";
if (!(!System.Text.RegularExpressions.Regex.IsMatch(entry.Text, numregex) || entry.Text == ""))
{
if (entry.Text.Length >= 1)
{
var index = entryList.IndexOf(entry);
var nextIndex = (index + 1) >= entryList.Count ? 0 : index + 1;
var next = entryList.ElementAt(nextIndex);
if (entry == ConfirmPasswordTwo)
{ }
else
{
next?.Focus();
}
}
}
//else
//{
// var index = entryList.IndexOf(entry);
// var prevIndex = (index) == 0 ? 0 : index - 1;
// var prev = entryList.ElementAt(prevIndex);
// if (entry == PasswordOne)
// { }
// else
// {
// prev?.Focus();
// }
//}
}
private void CustomEntry_OnBackspace(object sender, EventArgs e)
{
const string numregex = "^[0-9]+$";
if (!(System.Text.RegularExpressions.Regex.IsMatch(entry.Text, numregex) || entry.Text == ""))
{
var last = entryList.ElementAt(entryList.Count - 1);
last?.Focus();
}
else
{
return;
}
}
}
.xml
<local:CustomEntry
x:Name="PasswordOne"
IsPassword="True"
Keyboard="Numeric"
MaxLength="1"
ReturnType="Next"
TextChanged="Entry_FieldChanged"
OnBackspace="CustomEntry_OnBackspace"
Unfocused="Password_Unfocused" />