In previous post, I talked about creating a BorderlessEntry
view using a Custom Renderer (or an alternative Effect
). We are going to use said control in this post, so you can find it here: Xamarin.Forms Borderless Entry
On top of this control, we are also going to use a custom behavior mentioned in a blog post here: Xamarin.Tips – Restrict the Length of Your Entry Text
Now let’s talk about giving your users the ability to create a PIN to secure their account in your app while giving them a nice experience. The solution is the PinView
!
We are going to build this as a custom component in Xamarin.Forms:
PinView.xaml
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:behaviors="clr-namespace:YOUR_NAMESPACE.Behaviors;assembly=YOUR_NAMESPACE" xmlns:views="clr-namespace:YOUR_NAMESPACE;assembly=YOUR_NAMESPACE" x:Class="YOUR_NAMESPACE.PinView"> <ContentView.Resources> <ResourceDictionary> <Style x:Key="PinEntry" TargetType="Entry"> <Setter Property="Keyboard" Value="Numeric"/> <Setter Property="IsPassword" Value="True"/> <Setter Property="WidthRequest" Value="50"/> <Setter Property="HeightRequest" Value="50"/> <Setter Property="Margin" Value="8,0"/> <Setter Property="HorizontalTextAlignment" Value="Center"/> </Style> <Style x:Key="BottomBar" TargetType="BoxView"> <Setter Property="HeightRequest" Value="2"/> <Setter Property="BackgroundColor" Value="White"/> <Setter Property="WidthRequest" Value="50"/> <Setter Property="VerticalOptions" Value="Start"/> <Setter Property="Margin" Value="0"/> </Style> </ResourceDictionary> </ContentView.Resources> <ContentView.Content> <StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand"> <StackLayout Orientation="Vertical"> <views:BorderlessEntry x:Name="Pin1" Style="{StaticResource PinEntry}" TextColor="White"> <Entry.Behaviors> <behaviors:EntryLengthValidatorBehavior MaxLength="1"/> </Entry.Behaviors> </views:BorderlessEntry> <BoxView Style="{StaticResource BottomBar}"/> </StackLayout> <StackLayout Orientation="Vertical"> <views:BorderlessEntry x:Name="Pin2" Style="{StaticResource PinEntry}" TextColor="White"> <Entry.Behaviors> <behaviors:EntryLengthValidatorBehavior MaxLength="1"/> </Entry.Behaviors> </views:BorderlessEntry> <BoxView Style="{StaticResource BottomBar}"/> </StackLayout> <StackLayout Orientation="Vertical"> <views:BorderlessEntry x:Name="Pin3" Style="{StaticResource PinEntry}" TextColor="White"> <Entry.Behaviors> <behaviors:EntryLengthValidatorBehavior MaxLength="1"/> </Entry.Behaviors> </views:BorderlessEntry> <BoxView Style="{StaticResource BottomBar}"/> </StackLayout> <StackLayout Orientation="Vertical"> <views:BorderlessEntry x:Name="Pin4" Style="{StaticResource PinEntry}" TextColor="White"> <Entry.Behaviors> <behaviors:EntryLengthValidatorBehavior MaxLength="1"/> </Entry.Behaviors> </views:BorderlessEntry> <BoxView Style="{StaticResource BottomBar}"/> </StackLayout> </StackLayout> </ContentView.Content> </ContentView>
Lastly, we add some behaviors to our code-behind:
PinView.xaml.cs
public partial class PinView : ContentView { public static BindableProperty PinProperty = BindableProperty.Create("Pin", typeof(string), typeof(PinView), defaultBindingMode: BindingMode.OneWayToSource); public string Pin { get { return (string)GetValue(PinProperty); } set { SetValue(PinProperty, value); } } public PinView() { InitializeComponent(); Pin = string.Empty; Pin1.TextChanged += Pin1_TextChanged; Pin2.TextChanged += Pin2_TextChanged; Pin3.TextChanged += Pin3_TextChanged; Pin4.TextChanged += Pin4_TextChanged; } private void Pin4_TextChanged(object sender, TextChangedEventArgs e) { if (Pin4.Text.Length > 0) Pin4.Unfocus(); else Pin3.Focus(); Pin = Pin1.Text + Pin2.Text + Pin3.Text + Pin4.Text; } private void Pin3_TextChanged(object sender, TextChangedEventArgs e) { if (Pin3.Text.Length > 0) Pin4.Focus(); else Pin2.Focus(); Pin = Pin1.Text + Pin2.Text + Pin3.Text + Pin4.Text; } private void Pin2_TextChanged(object sender, TextChangedEventArgs e) { if (Pin2.Text.Length > 0) Pin3.Focus(); else Pin1.Focus(); Pin = Pin1.Text + Pin2.Text + Pin3.Text + Pin4.Text; } private void Pin1_TextChanged(object sender, TextChangedEventArgs e) { if (Pin1.Text.Length > 0) Pin2.Focus(); Pin = Pin1.Text + Pin2.Text + Pin3.Text + Pin4.Text; } }
If we dig into the behavior, we set up our TextChanged
events so that when each separate Entry
is updated, we move the focus to the next Entry
. If we clear the text of one of the Entries
, we move to the Entry
before it, and when we write text into the Entry
, we move to the next one.
We also use the Behavior mentioned to restrict the user from entering more than 1 character in each Entry
!
If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!