13
votes

I've read the many posts on the forum and on StackOverflow and other places on making custom keyboards, but have not found an approach that will work for my Xamarin forms cross-platform project. It is programmatically generated.

For example, I built this keyboard that was recommended in several places:

I try to integrate this into my Xamarin forms app but not able to do this

https://github.com/Vaikesh/CustomKeyboard/blob/master/CustomKeyboard/Activity1.cs

It works fine as a standalone

I want Hebrew language keyboard in my application Like this

enter image description here

I would appreciate any help.

Thank you.

1
You need implement this function in native platform, then you could use Custom Renderers to use it in Xamarin.Forms.Eren Shen
How can I create custom renders for keyboard?Ziyad Godil
Yes I do custom render for entry but how can I do for keyboard? Can you share some code me If I am put bounty for this? I want look like this play.google.com/store/apps/…Ziyad Godil
I will try my best to help you solve this problem.Eren Shen

1 Answers

9
votes

Custom Keyboard in Xamarin forms

You could create a PageRenderer and use native .axml layout file to create the custom Keyboard.

For example, my KeyboardPageRenderer :

[assembly: ExportRenderer(typeof(MyKeyboardPage), typeof(KeyboardPageRenderer))]
...
public class KeyboardPageRenderer : PageRenderer
{

    public CustomKeyboardView mKeyboardView;
    public EditText mTargetView;
    public Android.InputMethodServices.Keyboard mKeyboard;
    Activity activity;
    global::Android.Views.View view;

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

        if (e.OldElement != null || Element == null)
        {
            return;
        }

        try
        {
            SetupUserInterface();
            SetupEventHandlers();
            this.AddView(view);
        }
        catch (System.Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(@"           ERROR: ", ex.Message);
        }
    }

    void SetupUserInterface()
    {
        activity = this.Context as Activity;
        view = activity.LayoutInflater.Inflate(Resource.Layout.activity_keyboard, this, false);

        mKeyboard = new Android.InputMethodServices.Keyboard(Context, Resource.Xml.keyboard);
        mTargetView = view.FindViewById<EditText>(Resource.Id.target);

        mKeyboardView = view.FindViewById<CustomKeyboardView>(Resource.Id.keyboard_view);
        mKeyboardView.Keyboard = mKeyboard;
    }

    void SetupEventHandlers()
    {
        mTargetView.Touch += (sender, e) =>
        {
            ShowKeyboardWithAnimation();
            e.Handled = false;
            mTargetView.ShowSoftInputOnFocus = false;
        };

        mKeyboardView.Key += async (sender, e) =>
        {
            long eventTime = JavaSystem.CurrentTimeMillis();
            KeyEvent ev = new KeyEvent(eventTime, eventTime, KeyEventActions.Down, e.PrimaryCode, 0, 0, 0, 0, KeyEventFlags.SoftKeyboard | KeyEventFlags.KeepTouchMode);

            DispatchKeyEvent(ev);

            await Task.Delay(1);

            mTargetView.RequestFocus();
        };
    }


    public void ShowKeyboardWithAnimation()
    {
        if (mKeyboardView.Visibility == ViewStates.Gone)
        {
            mKeyboardView.Visibility = ViewStates.Visible;
            Android.Views.Animations.Animation animation = AnimationUtils.LoadAnimation(
                Context,
                Resource.Animation.slide_in_bottom
            );
            mKeyboardView.ShowWithAnimation(animation);
        }
    }

    protected override void OnLayout(bool changed, int l, int t, int r, int b)
    {
        base.OnLayout(changed, l, t, r, b);

        var msw = MeasureSpec.MakeMeasureSpec(r - l, MeasureSpecMode.Exactly);
        var msh = MeasureSpec.MakeMeasureSpec(b - t, MeasureSpecMode.Exactly);

        view.Measure(msw, msh);
        view.Layout(0, 0, r - l, b - t);
    }
}

Effect:

Sample implementation[Effect].

I wrote up a simple demo about how to implement this feature, you can see it in this GitHub Repository.

I don't know Hebrew, if you need to achieve the effect like the picture you have post, you need custom the layout in keyboard.xml file.

Update :

I am done iOS portion using entry render so only try to do for android portion

I write a EntryRenderer to implement this feature, effect like this, hope this can help you.

public class MyEntry2Renderer :  ViewRenderer<MyEntry, TextInputLayout>,
    ITextWatcher,
    TextView.IOnEditorActionListener
{
    private bool _hasFocus;

    public CustomKeyboardView mKeyboardView;
    public Android.InputMethodServices.Keyboard mKeyboard;

    ViewGroup activityRootView;

    protected EditText EditText => Control.EditText;

    public bool OnEditorAction(TextView v, ImeAction actionId, KeyEvent e)
    {
        if ((actionId == ImeAction.Done) || ((actionId == ImeAction.ImeNull) && (e.KeyCode == Keycode.Enter)))
        {
            Control.ClearFocus();
            //HideKeyboard();
            ((IEntryController)Element).SendCompleted();
        }
        return true;
    }

    public virtual void AfterTextChanged(IEditable s)
    {
    }

    public virtual void BeforeTextChanged(ICharSequence s, int start, int count, int after)
    {
    }

    public virtual void OnTextChanged(ICharSequence s, int start, int before, int count)
    {
        if (string.IsNullOrWhiteSpace(Element.Text) && (s.Length() == 0)) return;
        ((IElementController)Element).SetValueFromRenderer(Entry.TextProperty, s.ToString());
    }

    protected override TextInputLayout CreateNativeControl()
    {
        var textInputLayout = new TextInputLayout(Context);
        var editText = new EditText(Context);

        #region Add the custom Keyboard in your Page
        var activity = Forms.Context as Activity;
        var rootView = activity.Window.DecorView.FindViewById(Android.Resource.Id.Content);

        activity.Window.SetSoftInputMode(SoftInput.StateAlwaysHidden);

        activityRootView = ((ViewGroup)rootView).GetChildAt(0) as ViewGroup;
        mKeyboardView = new CustomKeyboardView(Forms.Context, null);

        Android.Widget.RelativeLayout.LayoutParams layoutParams =
            new Android.Widget.RelativeLayout.LayoutParams(LayoutParams.MatchParent, LayoutParams.WrapContent); // or wrap_content
        layoutParams.AddRule(LayoutRules.AlignParentBottom);
        activityRootView.AddView(mKeyboardView, layoutParams);
        #endregion

        //First open the current page, hide the Keyboard
        mKeyboardView.Visibility = ViewStates.Gone;

        //Use the custom Keyboard
        mKeyboard = new Android.InputMethodServices.Keyboard(Context, Resource.Xml.keyboard2);
        mKeyboardView.Keyboard = mKeyboard;

        mKeyboardView.Key += async (sender, e) =>
        {
            long eventTime = JavaSystem.CurrentTimeMillis();
            KeyEvent ev = new KeyEvent(eventTime, eventTime, KeyEventActions.Down, e.PrimaryCode, 0, 0, 0, 0, KeyEventFlags.SoftKeyboard | KeyEventFlags.KeepTouchMode);

            DispatchKeyEvent(ev);

            await Task.Delay(1);
        };

        textInputLayout.AddView(editText);
        return textInputLayout;
    }


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

        if (e.OldElement != null)
            if (Control != null)
                EditText.FocusChange -= ControlOnFocusChange;

        if (e.NewElement != null)
        {
            var ctrl = CreateNativeControl();
            SetNativeControl(ctrl);

            EditText.ShowSoftInputOnFocus = false;

            EditText.FocusChange += ControlOnFocusChange;
        }
    }

    private void ControlOnFocusChange(object sender, FocusChangeEventArgs args)
    {
        _hasFocus = args.HasFocus;
        if (_hasFocus)
        {
            EditText.Post(() =>
            {
                EditText.RequestFocus();
                ShowKeyboardWithAnimation();
            });
        }
        else
        {
            //Hide the Keyboard
            mKeyboardView.Visibility = ViewStates.Gone;
        }
    }

    public void ShowKeyboardWithAnimation()
    {
        if (mKeyboardView.Visibility == ViewStates.Gone)
        {
            mKeyboardView.Visibility = ViewStates.Visible;
            Android.Views.Animations.Animation animation = AnimationUtils.LoadAnimation(
                Context,
                Resource.Animation.slide_in_bottom
            );
            mKeyboardView.ShowWithAnimation(animation);
        }
    }
}