Xamarin.Forms Tip - Implement Show/Hide Password Using Effects

While developing login pages, we usually get a requirement that there should be an icon in password entry to show/hide password while entering the password. While looking for a solution to this requirement, I found that most of the implementation is done using custom controls whereas we can do this kind of small platform-specific customization using effects. Last year, I wrote this article about implementing custom fonts using effects so I thought let's try this also using the same tecnique.

While developing login pages, we usually get a requirement that there should be an icon in password entry to show/hide password while entering the password. While looking for a solution to this requirement, I found that most of the implementations are done using custom controls whereas we can do this kind of small platform-specific customization using effects. Last year, I wrote this article about implementing custom fonts using effects, so I thought let's try this also using the same technique

Creating the Effect

Changes in PCL project

Create a new class file named ‘ShowHidePassEffect’ and add the following code to it.

  1. public class ShowHidePassEffect : RoutingEffect  
  2. {  
  3.             public string EntryText { get; set; }  
  4.     public ShowHidePassEffect() : base("Xamarin.ShowHidePassEffect"){}  
  5. }  

In the above mentioned code, we are creating a custom effect where we are creating a new property named ‘EntryText’ to show the entered password text. The implementation of this effect will have to be written in Platform specific projects.

Changes in Android project

In your Android project, create a new class file named ‘ShowHidePassEffect’ and add the following code into it.

  1. using Android.Text.Method;  
  2. using Android.Views;  
  3. using Android.Widget;  
  4. using Xamarin.Forms;  
  5. using Xamarin.Forms.Platform.Android;  
  6.    
  7. [assembly: ResolutionGroupName("Xamarin")]  
  8. [assembly: ExportEffect(typeof(ShowHidePassEx.Droid.Effects.ShowHidePassEffect), "ShowHidePassEffect")]  
  9. namespace ShowHidePassEx.Droid.Effects  
  10. {  
  11.     public class ShowHidePassEffect : PlatformEffect  
  12.     {  
  13.    
  14.    
  15.         protected override void OnAttached()  
  16.         {  
  17.             ConfigureControl();  
  18.         }  
  19.    
  20.         protected override void OnDetached()  
  21.         {  
  22.         }  
  23.    
  24.         private void ConfigureControl()  
  25.         {  
  26.             EditText editText = ((EditText)Control);  
  27.             editText.SetCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, Resource.Drawable.ShowPass, 0);  
  28.             editText.SetOnTouchListener(new OnDrawableTouchListener());  
  29.    
  30.         }  
  31.     }  
  32.    
  33.     public class OnDrawableTouchListener : Java.Lang.Object, Android.Views.View.IOnTouchListener  
  34.     {  
  35.         public bool OnTouch(Android.Views.View v, MotionEvent e)  
  36.         {  
  37.             if (v is EditText && e.Action == MotionEventActions.Up)  
  38.             {  
  39.                 EditText editText = (EditText)v;  
  40.                 if (e.RawX >= (editText.Right - editText.GetCompoundDrawables()[2].Bounds.Width()))  
  41.                 {  
  42.                     if (editText.TransformationMethod == null)  
  43.                     {  
  44.                         editText.TransformationMethod = PasswordTransformationMethod.Instance;  
  45.                         editText.SetCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, Resource.Drawable.ShowPass, 0);  
  46.                     }  
  47.                     else  
  48.                     {  
  49.                         editText.TransformationMethod = null;  
  50.                         editText.SetCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, Resource.Drawable.HidePass, 0);  
  51.                     }  
  52.    
  53.                     return true;  
  54.                 }  
  55.             }  
  56.    
  57.             return false;  
  58.         }  
  59.     }  
  60. }  
In the above-mentioned Android implementation of the effect, we are adding the code to create the control manually in ‘OnDrawableTouchListener’ method where, we are adding the ShowPass and HidePass icons to the entry control, changing them on the basis of user touch action and attaching it on effect invocation which will be fired when the effect is added to the control.

Before writing this code, make sure that you have ShowPass and HidePass images in your Resources/Drawable folder of Android project, like in the following image.

Xamarin

These images can be downloaded from the internet, or your project’s designer can provide it.

Changes in Android project

Similarly, in your iOS project, create a new class file named ‘ShowHidePassEffect’ and add the following code.

  1. using System;  
  2. using ShowHidePassEx.iOS.Effects;  
  3. using UIKit;  
  4. using Xamarin.Forms;  
  5. using Xamarin.Forms.Platform.iOS;  
  6.    
  7.    
  8. [assembly: ResolutionGroupName("Xamarin")]  
  9. [assembly: ExportEffect(typeof(ShowHidePassEffect), "ShowHidePassEffect")]  
  10. namespace ShowHidePassEx.iOS.Effects  
  11. {  
  12.     public class ShowHidePassEffect: PlatformEffect  
  13.     {  
  14.           
  15.         protected override void OnAttached()  
  16.         {  
  17.             ConfigureControl();  
  18.         }  
  19.    
  20.         protected override void OnDetached()  
  21.         {  
  22.                
  23.         }  
  24.    
  25.         private void ConfigureControl()  
  26.         {  
  27.             if (Control != null)  
  28.             {  
  29.                 UITextField vUpdatedEntry = (UITextField)Control;  
  30.                 var buttonRect = UIButton.FromType(UIButtonType.Custom);  
  31.                 buttonRect.SetImage(new UIImage("ShowPass"), UIControlState.Normal);  
  32.                 buttonRect.TouchUpInside += (object sender, EventArgs e1) =>  
  33.                 {  
  34.                     if (vUpdatedEntry.SecureTextEntry)  
  35.                     {  
  36.                         vUpdatedEntry.SecureTextEntry = false;  
  37.                         buttonRect.SetImage(new UIImage("HidePass"), UIControlState.Normal);  
  38.                     }  
  39.                     else  
  40.                     {  
  41.                         vUpdatedEntry.SecureTextEntry = true;  
  42.                         buttonRect.SetImage(new UIImage("ShowPass"), UIControlState.Normal);  
  43.                     }  
  44.                 };  
  45.    
  46.                 vUpdatedEntry.ShouldChangeCharacters += (textField, range, replacementString) =>  
  47.                 {  
  48.                     string text = vUpdatedEntry.Text;  
  49.                     var result = text.Substring(0, (int)range.Location) + replacementString + text.Substring((int)range.Location + (int)range.Length);  
  50.                     vUpdatedEntry.Text = result;  
  51.                     return false;  
  52.                 };  
  53.    
  54.    
  55.                 buttonRect.Frame = new CoreGraphics.CGRect(10.0f, 0.0f, 15.0f, 15.0f);  
  56.                 buttonRect.ContentMode = UIViewContentMode.Right;  
  57.    
  58.                 UIView paddingViewRight = new UIView(new System.Drawing.RectangleF(5.0f, -5.0f, 30.0f, 18.0f));  
  59.                 paddingViewRight.Add(buttonRect);  
  60.                 paddingViewRight.ContentMode = UIViewContentMode.BottomRight;  
  61.    
  62.    
  63.                 vUpdatedEntry.LeftView = paddingViewRight;  
  64.                 vUpdatedEntry.LeftViewMode = UITextFieldViewMode.Always;  
  65.    
  66.                 Control.Layer.CornerRadius = 4;  
  67.                 Control.Layer.BorderColor = new CoreGraphics.CGColor(255, 255, 255);  
  68.                 Control.Layer.MasksToBounds = true;  
  69.                 vUpdatedEntry.TextAlignment = UITextAlignment.Left;  
  70.             }  
  71.    
  72.         }  
  73.     }  
  74. }  
In the above-mentioned iOS implementation of the effect, we are adding the code to create the control manually in 'ConfigureControl' method where we are adding the ShowPass and HidePassicons to the entry control, changing them on the basis of user touch action; and attaching it on effect invocation which will be fired when the effect will be added to the control.

Just like Android, here too, make sure that you have ShowPass and HidePass images in your Resources folder of iOS project.

Xamarin

Using the Effect

In order to use the effect, we will just have to add the effect to the entry control in XAML like in the following code.

  1. <Entry IsPassword="true" Placeholder="Password" Text="Password">  
  2.     <Entry.Effects>  
  3.         <ef:ShowHidePassEffect />  
  4.     </Entry.Effects>  
  5. </Entry>  

And, if you want to use it inside your C# code, you can do that like this.

  1. var vPasswordEntry = new Entry() { IsPassword=true };  
  2. vPasswordEntry.Effects.Add(new FontEffect());  

This is the sample application whose code is published on Github. It looks something like the following when executed.

iOS Simulator

Xamarin

Android Simulator

Xamarin

This is one simple tip to implement Show/Hide password feature in your Xamarin.Forms mobile apps. I will try to come up with more such tips in future. Let me know if I have missed anything or you have any suggestions/concerns/queries.