androidxamarin.formskeyboardrendererxamarin.forms.entry

Changing keyboard's ImeOptions of Xamarin.Forms.Entry in custom renderer not working on Android


What I have:

I have a custom class MyEntry derived from Xamarin.Forms.Entry and custom renderer classes MyEntryRenderer for Android and iOS.

What I want:

I want to change the keyboard's "enter"-button to a "search"-button by changing ImeOptions on Android and ReturnKeyType on iOS (see sample code). When I press the altered "search"-button, the MyEntry.Completed event should be called (like before when I pressed the un-altered "enter"-button.

What really happens:

On iOS the code works like expected. But on Android nothing happens. The event doesn't get called.

My question:

How can I achieve what I described above on Android?

Sample code:

App.cs:

namespace CustomEntry
{
    public class App
    {
        public static Page GetMainPage()
        {    
            MyEntry entry = new MyEntry {
                VerticalOptions = LayoutOptions.CenterAndExpand,
                HorizontalOptions = LayoutOptions.CenterAndExpand,
                Placeholder = "Enter some text"
            };

            entry.Completed += delegate {
                Console.WriteLine("Completed");
            };

            return new ContentPage { 
                Content = entry,
            };
        }
    }
}

MyEntry.cs:

namespace CustomEntry
{
    public class MyEntry:Entry
    {

    }
}

MyEntryRenderer.cs (Android):

[assembly: ExportRenderer(typeof(MyEntry), typeof(MyEntryRenderer))]
namespace CustomEntry.Android
{
    public class MyEntryRenderer:EntryRenderer
    {

        protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
        {
            base.OnElementChanged(e);

            if (Control != null) { 
                Control.ImeOptions = global::Android.Views.InputMethods.ImeAction.Search;
            }
        }

    }
}

MyEntryRenderer.cs (iOS):

[assembly: ExportRenderer(typeof(MyEntry), typeof(MyEntryRenderer))]
namespace CustomEntry.iOS
{
    public class MyEntryRenderer:EntryRenderer
    {

        protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
        {
            base.OnElementChanged(e);

            if (Control != null) {
                Control.ReturnKeyType = UIReturnKeyType.Search;
            }
        }

    }
}

Solution

  • I found a workaround for my problem myself:

    First I added an Action to my custom entry to be called when I press my "search"-button.

    MyEntry.cs

    namespace CustomEntry
    {
        public class MyEntry:Entry
        {
            public Action SearchPressed = delegate {
            };
        }
    }
    

    Second I "listen" for ImeAction.Search like this and call the Action I added to my custom entry.

    MyEntryRenderer.cs (Android):

    [assembly: ExportRenderer(typeof(MyEntry), typeof(MyEntryRenderer))]
    namespace CustomEntry.Android
    {
        public class MyEntryRenderer:EntryRenderer
        {
    
            protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
            {
                base.OnElementChanged(e);
    
                if (Control != null) {
                    Control.ImeOptions = ImeAction.Search;
                    Control.EditorAction += (sender, args) => {
                        if (args.ActionId == ImeAction.Search) {
                            var entry = (AddressEntry)Element;
                            entry.SearchPressed();
                        }
                    };
                }
            }
    
        }
    }
    

    In a third class where I use MyEntry I can run some code when the "search"-button is pressed like this:

    var myEntry = new MyEntry();
    myEntry.SearchPressed += SomeMethod;