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!