Ever wished if your Xamarin.Forms Password Entry control had the option to reveal, or show the Password text that the User types on demand, instead of the black dots? 😉 Even better, without any Custom Renderers or Platform Specific code? Welcome to another lightening short post of me hacking around Xamarin.Forms elements!
So in Xamarin.Forms to enable this feature usually you need to resort to creating Custom Renderers or some platform specific implementation, which is a tedious process and a complicated implementation. So I thought of making use of my own crazy imagination and hack my way around to get this to work right from Xamarin.Forms itself!
No custom renderers, no platform specific code and no third party libraries! Just by using pure out of the box Xamarin.Forms! 😉
Sneak Peak!
That’s what we gonna be build yol!
XFHACKS Recipe!
Let the recipe begin! So basically the idea here is to have two Entry elements which represents the Entry with IsPassword enabled and another Entry with IsPassword disabled, laid on top of each other inside a Grid layout. Also we’re going to switch the visibility of these two Entry controls on a Button click event which will also be laid on top of both the Entry elements, aligned to the right most corner of the whole Grid layout. Just to add some cheery to the icing, let’s have a Button with an Icon Image inside of it, which implementation I’ll be extracting from one of my previous XFHACKS articles, XFHACKS-005 Button with full control on Text and Icon! ! Give it a read if you’re curious! 😉
Since we’re maintaining two Entry elements, we need to make sure both of them have the same Text value at any point of the user’s interaction. So to make this happen we’re going use Element to Element binding in Xamarin.Forms, where as we are binding the Text field properties of both Entry controls to eachother. Thereby one Entry’s Text changes immediately reflects on the other one and so on.
Just to show some love for my architectural practices, I’m going to move the whole Button click event and the handling of the behavior logic of this control into a TriggerAction, aha! separation of concern or loosely coupled and no direct code behind dependency allowing for more re-usability! 😀
Code!
Behold the golden XAML code!
<Grid Grid.Row="1" Grid.Column="0" HeightRequest="45" HorizontalOptions="FillAndExpand" IsClippedToBounds="True"> <!-- Entry Password --> <Entry x:Name="EntryPassword" Grid.Row="0" Grid.Column="0" FontSize="Medium" IsPassword="True" IsVisible="True" Keyboard="Plain" Placeholder="Password" Text="{Binding Source={x:Reference EntryText}, Path=Text, Mode=TwoWay}" /> <!-- Entry Text --> <Entry x:Name="EntryText" Grid.Row="0" Grid.Column="0" FontSize="Medium" IsPassword="False" IsVisible="False" Keyboard="Plain" Placeholder="Password" Text="{Binding Source={x:Reference EntryPassword}, Path=Text, Mode=TwoWay}" /> <!-- Button with Icon --> <Grid Grid.Row="0" Grid.Column="0" Padding="0,0,3,0" HeightRequest="27" HorizontalOptions="End" IsClippedToBounds="True" VerticalOptions="Center" WidthRequest="35"> <!-- Button Control --> <Button x:Name="ShowPasswordButton" BackgroundColor="White"> <Button.Margin> <OnPlatform x:TypeArguments="Thickness"> <On Platform="Android" Value="-4,-6,-4,-6" /> <On Platform="iOS" Value="0" /> </OnPlatform> </Button.Margin> <Button.Triggers> <EventTrigger Event="Clicked"> <triggers:ShowPasswordTriggerAction EntryPasswordName="EntryPassword" EntryTextName="EntryText" IconImageName="ShowPasswordButtonIcon" /> </EventTrigger> </Button.Triggers> </Button> <!-- Icon Image --> <Image x:Name="ShowPasswordButtonIcon" HeightRequest="25" HorizontalOptions="Fill" InputTransparent="True" Source="{extensions:ImageResource XFHacks.Resources.showpasswordicon.png}" VerticalOptions="Fill" WidthRequest="25" /> </Grid> </Grid>
Here we go, explanation time! So the two Entry elements are laying on top of each other and bound to each other’s Text properties, while having one Entry as IsPassword=true and the other opposite. I have given names for the Elements because we need references of them to handle the behaviour inside our TriggerAction which I will show next.
Then the Button with the Icon Image Element is aligned to the very right corner of Parent layout, laying on top of both Entry elements. I have added some padding to it to avoid it conflicting with the border of the Entry in iOS and UWP, then for Android it shouldn’t really matter visually. There’s a HeightRequest=”27″ and WidthRequest=”35″ given to this Element group because I needed to have some horizontal space besides the Image icon visually. For the Image we’re using a EmbeddedResource type image, which makes things really easy for managing the Images.
Then for the Parent Grid Layout that holds all of these Elements together,is using IsClippedToBounds property to make sure everything holds inside the Bounds of the Grid as a single UI Element.
This is the most crucial part where inside the Button click event we’re invoking a TrigerAction called ShowPasswordTriggerAction which handles all the logic and behaviour of this custom control. And we’re passing in the names of the Elements we have assigned, into the Trigger so that we can look it up inside the TriggerAction, retrieve their runtime references and handle the behavior as we need. Pretty straightforward implementation there 😉
Next let’s look into the golden TriggerAction!
/// <summary> /// The Trigger Action that will handle /// the Show/Hide Passeword text /// </summary> public class ShowPasswordTriggerAction : TriggerAction<Button> { public string IconImageName { get; set; } public string EntryPasswordName { get; set; } public string EntryTextName { get; set; } protected override void Invoke(Button sender) { // get the runtime references // for our Elements from our custom control var imageIconView = ((Grid) sender.Parent) .FindByName<Image>(IconImageName); var entryPasswordView = ((Grid) ((Grid) sender.Parent).Parent).FindByName<Entry>(EntryPasswordName); var entryTextView = ((Grid)((Grid)sender.Parent).Parent).FindByName<Entry>(EntryTextName); // Switch visibility of Password // Entry field and Text Entry fields entryPasswordView.IsVisible = !entryPasswordView.IsVisible; entryTextView.IsVisible = !entryTextView.IsVisible; // update the Show/Hide button Icon states if (entryPasswordView.IsVisible) { // Password is not Visible state imageIconView.Source = ImageSource.FromResource( "XFHacks.Resources.showpasswordicon.png", Assembly.GetExecutingAssembly()); // Setting up Entry curser focus entryPasswordView.Focus(); entryPasswordView.Text = entryTextView.Text; } else { // Password is Visible state imageIconView.Source = ImageSource.FromResource( "XFHacks.Resources.hidepasswordicon.png", Assembly.GetExecutingAssembly()); // Setting up Entry curser focus entryTextView.Focus(); entryTextView.Text = entryPasswordView.Text; } } }
Here’s the most important bit where we’re handling the behaviour logic of our awesome Password Entry Control! At the moment of Invoking the Button click we’re doing a simple FindByName<T> look up for our required Elements, that are the EntryPassword field, EntryText field, and the IconImage.
First of all we’re setting the visibility of the two Entry Elements opposite for each other, as in if the User clicks on Show Password state, then the Entry with Text property will be displayed, and the user clicks on Hide Password state then the Entry with Password property (black dots) will be displayed.
Then based on the state, we’re updating the button icon’s Image source, as you can see we’re setting the showpasswordicon.png and hidepasswordicon.png respectively depending on the current state.
Finally we’re doing something extra to make sure whatever the visible the Entry element is still on Focus after the switching of the Password visibility state.
There we go, pretty straight forward yeah!
Important: You could also move that whole piece of XAML to a separate XAML file, so that you could set it up as a reusable Control in your project! 😉
Fire it up!
Alright let’s see this in action!
There you have it running on Android, iOS and UWP like a charm! 😀
NO CUSTOM RENDERERS! NO NATIVE CODE! MORE AWESOME! xD
Grab it on Github!
https://github.com/UdaraAlwis/XFHacks
Well then, that’s it for now. More awesome stuff on the way!
Cheers! 😀 share the love!
Improvement suggestion: I was discussing this with one of my colleagues and he pointed out an awesome tweak for a much better improvement, that is to use the same implementation with trigger and all but with a single Entry element with the IsPassword true and false state on demand instead of using two Entry elements. This is a great idea yet so simple, which will drastically improve the rendering performance. So if you wanna give it a crack please go ahead! And here’s a shout out to an awesome developer Akshay Kulkarni – ak47akshaykulkarni, make sure to check out his Github repo! 😉