Xamarin Forms / Android: Backspace detektálása az Entrykben

Ahhoz, hogy a szoftveres / hardveres billentyűzeten ütött vissza gomb érzékelését detektáljuk a billentyűzeten, szükségünk lesz egy CustomRenderer-re, ahhoz pedig egy Entry száramaztatáshoz a közös kódban:

public class CustomEntry: Entry
{
    public delegate void BackspaceEventHandler(object sender, EventArgs e);

    public event BackspaceEventHandler OnBackspace;

    public CustomEntry() { }

    public void OnBackspacePressed() 
    {
        if (OnBackspace != null)
        {
            OnBackspace(null, null);
        }
    }
}

Két CustomRenderer megoldás is van Androidon. Az egyik, amelyik magát a Renderert egy InputFilter implementációvá teszi, a másik, amely egy csak egy metódust overrideol. A különbség köztük, hogy a DispatchKeyEvent override az üres entry esetén is továbbítja az eventet, míg az inputfiilter csak akkor érzékeli a visszatörlés gombnyomást, ha volt már szöveg benne.

DispatchKeyEvent override megoldás

public class CustomEntryRenderer: EntryRenderer
 {
    public override bool DispatchKeyEvent(KeyEvent e)
    {
        if (e.Action == KeyEventActions.Down)
        {
            if (e.KeyCode == Keycode.Del)
            {
                if (string.IsNullOrWhiteSpace(Control.Text))
                {
                    var entry = (PasswordBox)Element;
                    entry.OnBackspacePressed();
                }
            }
        }
        return base.DispatchKeyEvent(e);
    }

    protected override void 
    OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Entry> e)
    {
        base.OnElementChanged(e);
    }
}

InputFilter implementáció

[assembly: ExportRenderer(typeof(CustomEntry), typeof(CustomEntryRenderer))]
namespace App.Droid.Renderers
{
    public class CustomEntryRenderer: EntryRenderer, Android.Text.IInputFilter
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
        {
            base.OnElementChanged(e);

            if (Control == null) 
            {
                return;
            }

            Control.SetFilters(new IInputFilter[] { this });

        }

        ICharSequence IInputFilter.FilterFormatted(ICharSequence source, int start, int end, ISpanned dest, int dstart, int dend)
        {
            if (string.IsNullOrWhiteSpace(source.ToString()))
            {
                var entry = (CustomEntry)Element;
                entry.OnBackspacePressed();
            }
            return source;
        }

    }
}

Xamarin iOS: Entry Unfocus event nem triggerelődik, ListView-el.

Ha egy Entry épp focus alatt van, és úgy választunk egy listaelemet a ListView-ből, az Entry Unfocus eventje nem fog triggerelődni. Ez azért van, mert a ListView a Touch eseményt ilyenkor elnyeli. Az én esetemben a megoldás ListView mögött egy háttérszínnel rendelkező grid volt, ami képes touch eventeket elkapni. A ListView InputTransparent tulajdonságának True-ra állításával ez a probléma megoldódott, mert az alatta lévő grid fókuszt kapott, és “mintha kikattintottunk volna” a gridből, az entry focusa megszűnt.

        <ListView
            x:Name="list"
            BackgroundColor="#393939"
            ItemTapped="list_ItemTapped"

            InputTransparent="True"

            ItemsSource="{Binding Path=AutoCompleteItems, Source={x:Reference UserControl}}"
            SelectedItem="{Binding Path=SelectedAddress, Source={x:Reference UserControl}}"
            SeparatorVisibility="None">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <usercontrols:AddressSelectorAutoCompleteItemDataTemplate />
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>

Próbáltam a ListView ItemSelectedjében unfocusolni az Entry Controlokat, azonban ez nem hozott sikert.

Xamarin Android: TextView / Entry padding eltávolítása

Ha az iOS Entry láthatólag nem tartalmaz margót vagy paddingot, de Androidon máshogy renderelődik ki, akkor gyanakodhatunk arra, hogy valahol nem állítottunk a Xamarin.Forms kódban margót/paddingot nullára. Azonban a Forms Paddingjával és Marginjával nem állítható az androidos TextView paddingja, ehhez customrenderer-re lesz szükség.

[assembly: ExportRenderer(typeof(CustomEntry), typeof(CustomEntry Renderer))]
namespace banditoth.Droid.Renderers
{
    public class CustomEntryRenderer : EntryRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
        {
            base.OnElementChanged(e);

            if (Control != null)
            {
                // Eltávolítjuk a paddingot.
                Control.SetPadding(0, 0, 0, 0);
            }
        }
    }
}

A Control.SetPaddinggal Custom értékeket állíthatunk be a natív TextView paddingjának. Nekem most az eltávolításra volt szükségem, ezért kinulláztam.

Word Capitalisation Xamarin Forms Entryben

Amennyiben azt szeretnénk, hogy minden szóköz leütése után automatikusan nagybetűvel kezdje a szavakat a készülék-billentyűzet abban az esetben el kell nevezni az Entry-t, jelen esetben az Entryből származtatott UserControlt.

<blackandyellowdesign:UnderlinedEntryWithLabelOnRight
                    x:Name="FullNameEntry"
                    Placeholder="{markupextensions:Multilanguage TranslationKey=PlaceholderRegisterViewName}"
                    Text="{Binding Path=FullName}" />

Így hivatkozható CodeBehindban FullNameEntry-ként.

A konstruktorban (vagy tetszőleges helyre, valamilyen trigger esetén) pedig be kell állítani a Keyboard tulajdonságát, a Keyboard osztály statikus “Create” metódusának meghívásával.

        FullNameEntry.Keyboard = Keyboard.Create(KeyboardFlags.CapitalizeWord);