15/04/2020 Doru Bulubasa

Xamarin Forms – afisare parola in textbox

Image blog

Nu am mai scris de ceva vreme pe blog si nu pot spune ca din lipsa de timp, ci pur si simplu din lipsa de organizare a lui.

Acest articol este despre programare mobile, folosind Xamarin-ul cu Visual Studio 2019, pentru ca este cross platform: intr-o proportie destul de mare, scriem codul o singura data pentru toate sistemele de operare mobile (noi vom merge pe iOs si Android).

Spun intr-o proportie destul de mare, deoarce sunt anumite parti care trebuie scrise separate, pentru fiecare OS.

Vom scrie codul care ne da posibilitatea sa vedem cee ace am scris intr-un textbox tip parola.

In primul rand cream un nou proiect -> MyProject. Acesta va avea in final 3 proiecte: MyProject, MyProject.Android si MyProject.iOS.

Apoi vom crea un folder nou (Effects) in toate cele 3 proiecte din solutia noastra.  In fiecare din cele 3 foldere, vom crea o noua clasa cu numele ShowHidePassEffects.

Incepem cu clasa din proiectul MyProject. Aceasta va avea urmatorul continut:

using Xamarin.Forms;
namespace MyProject.Effects
{
    public class ShowHidePassEffect : RoutingEffect
    {
        public string EntryText { get; set; }
        public ShowHidePassEffect() : base("Xamarin.ShowHidePassEffect") { }
    }
}

Clasa din proiectul MyProject.Android va avea un continut mai mare:

using Android.Text.Method;
using Android.Views;
using Android.Widget;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ResolutionGroupName("Xamarin")]
[assembly: ExportEffect(typeof(MyProject
.Droid.Effects.ShowHidePassEffect), "ShowHidePassEffect")]

namespace MyProject.Droid.Effects
{
    public class ShowHidePassEffect : PlatformEffect
    {
        protected override void OnAttached()
        {
            ConfigureControl();
        }

        protected override void OnDetached()
        {
        }
        private void ConfigureControl()
        {
            EditText editText = ((EditText)Control);
            editText.SetCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, Resource.Drawable.HidePass, 0);
            editText.SetOnTouchListener(new OnDrawableTouchListener());
        }
    }
    public class OnDrawableTouchListener : Java.Lang.Object, Android.Views.View.IOnTouchListener
    {
        public bool OnTouch(Android.Views.View v, MotionEvent e)
        {
            if (v is EditText && e.Action == MotionEventActions.Up)
            {
                EditText editText = (EditText)v;
                if (e.RawX >= (editText.Right - editText.GetCompoundDrawables()[2].Bounds.Width()))
                {
                    if (editText.TransformationMethod == null)
                    {
                        editText.TransformationMethod = PasswordTransformationMethod.Instance;
                        editText.SetCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, Resource.Drawable.HidePass, 0);
                        editText.SetSelection(editText.Length());
                    }
                    else
                    {
                        editText.TransformationMethod = null;
                        editText.SetCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, Resource.Drawable.ShowPass, 0);
                        editText.SetSelection(editText.Length());
                    }
                    return true;
                }
            }
 
            return false;
        }
    }
}

In final, clasa din proiectul MyProject.iOS:

using System;
using MyProject.iOS.Effects;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ResolutionGroupName("Xamarin")]
[assembly: ExportEffect(typeof(ShowHidePassEffect), "ShowHidePassEffect")]
namespace MyProject.iOS.Effects
{
    public class ShowHidePassEffect : PlatformEffect
    {
        protected override void OnAttached()
        {
            ConfigureControl();
        }
        protected override void OnDetached()
        {
        }
        private void ConfigureControl()
        {
            if (Control != null)
            {
                UITextField vUpdatedEntry = (UITextField)Control;
                var buttonRect = UIButton.FromType(UIButtonType.Custom);
                buttonRect.SetImage(new UIImage("HidePass"), UIControlState.Normal);
                buttonRect.TouchUpInside += (object sender, EventArgs e1) =>
                {
                    if (vUpdatedEntry.SecureTextEntry)
                    {
                        vUpdatedEntry.SecureTextEntry = false;
                        buttonRect.SetImage(new UIImage("ShowPass"), UIControlState.Normal);
                    }
                    else
                    {
                        vUpdatedEntry.SecureTextEntry = true;
                        buttonRect.SetImage(new UIImage("HidePass"), UIControlState.Normal);
                    }
                };
                vUpdatedEntry.ShouldChangeCharacters += (textField, range, replacementString) =>
                {
                    string text = vUpdatedEntry.Text;
                    var result = text.Substring(0, (int)range.Location) + replacementString + text.Substring((int)range.Location + (int)range.Length);
                    vUpdatedEntry.Text = result;
                    return false;
                };
                buttonRect.Frame = new CoreGraphics.CGRect(10.0f, 0.0f, 15.0f, 15.0f);
                buttonRect.ContentMode = UIViewContentMode.Right;
                UIView paddingViewRight = new UIView(new System.Drawing.RectangleF(5.0f, -5.0f, 30.0f, 18.0f));
                paddingViewRight.Add(buttonRect);
                paddingViewRight.ContentMode = UIViewContentMode.BottomRight;

                vUpdatedEntry.LeftView = paddingViewRight;
                vUpdatedEntry.LeftViewMode = UITextFieldViewMode.Always;
                Control.Layer.CornerRadius = 4;
                Control.Layer.BorderColor = new CoreGraphics.CGColor(255, 255, 255);
                Control.Layer.MasksToBounds = true;
                vUpdatedEntry.TextAlignment = UITextAlignment.Left;
            }
        }
    }
}

Mai trebuie sa incarcam si cele 2 imagini de care avem nevoie: HidePass.png si ShowPass.png (pentru proiectul Android: Resources/drawable; pentru iOS: Resources).

 

Acum, avand cele 3 clase de mai sus si imaginile incarcate, ne intoarcem la proiectul MyProject. Tot ce mai avem de facut este sa aplicam efectul direct textbox-ului

<?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:ef="clr-namespace:MyProject.Effects"
             x:Class="MyProject.LoginPage">
        <StackLayout>
            <Grid Padding="0">
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <StackLayout Margin="10,0">
                    <Label Text="Log Into Your Account"/>
                    <Entry x:Name="UserName"          
                               Placeholder="User Name"/>

                    <Entry x:Name="Password"
                           IsPassword="true"
                           Placeholder="Password">
                        <Entry.Effects>
                            <ef:ShowHidePassEffect />
                        </Entry.Effects>
                    </Entry>
                    <Button x:Name="btnLogin"
                            Text="Login"/>
                </StackLayout>
            </Grid>
        </StackLayout>
</ContentPage>

Cam asta ar fi tot. Bafta!