首页 > 解决方案 > Popup Hides the Custom Keyboard in Xamarin.Forms

问题描述

I have designed a Custom Numerical Keyboard but It hides When I activate or use it on Popup Screen(used Rg.Plugin Popup). eg. Like thisImage describing when popup is above on the Keyboard / Popup hides the Keyboard

If I make this screen as the First Screen or If I make this into a Page/View, not the Popup. It looks like this eg., Image above the Page

This is the code I have written -

1- Custom Keyboard (Xamarin forms Custom Renderer)

public class EntryWithCustomKeyboard : Entry
{
    public static readonly BindableProperty EnterCommandProperty = BindableProperty.Create(
        nameof(EnterCommand),
        typeof(ICommand),
        typeof(EntryWithCustomKeyboard),
        default(ICommand),
        BindingMode.OneWay
    );

    public ICommand EnterCommand
    {
        get => (ICommand)GetValue(EnterCommandProperty);
        set => SetValue(EnterCommandProperty, value);
    }

    public static readonly BindableProperty BorderColorProperty =
    BindableProperty.Create(nameof(BorderColor),
   typeof(Color), typeof(CustomEntry), Color.Gray);
    // Gets or sets BorderColor value  
    public Color BorderColor
    {
        get => (Color)GetValue(BorderColorProperty);
        set => SetValue(BorderColorProperty, value);
    }

    public static readonly BindableProperty BorderWidthProperty =
    BindableProperty.Create(nameof(BorderWidth), typeof(int),
        typeof(CustomEntry), Device.OnPlatform<int>(1, 2, 2));
    // Gets or sets BorderWidth value  
    public int BorderWidth
    {
        get => (int)GetValue(BorderWidthProperty);
        set => SetValue(BorderWidthProperty, value);
    }
    public static readonly BindableProperty CornerRadiusProperty =
    BindableProperty.Create(nameof(CornerRadius),
        typeof(double), typeof(CustomEntry), Device.OnPlatform<double>(6, 7, 7));
    // Gets or sets CornerRadius value  
    public double CornerRadius
    {
        get => (double)GetValue(CornerRadiusProperty);
        set => SetValue(CornerRadiusProperty, value);
    }
    public static readonly BindableProperty IsCurvedCornersEnabledProperty =
    BindableProperty.Create(nameof(IsCurvedCornersEnabled),
        typeof(bool), typeof(CustomEntry), true);
    // Gets or sets IsCurvedCornersEnabled value  
    public bool IsCurvedCornersEnabled
    {
        get => (bool)GetValue(IsCurvedCornersEnabledProperty);
        set => SetValue(IsCurvedCornersEnabledProperty, value);
    }
}

2- Android Renderer for Custom Keyboard

    public class EntryWithCustomKeyboardRenderer : EntryRenderer, IOnKeyboardActionListener
    {
        PopupWindow popup;
        private Context context;

        private EntryWithCustomKeyboard entryWithCustomKeyboard;

        private Android.InputMethodServices.KeyboardView mKeyboardView;
        private Android.InputMethodServices.Keyboard mKeyboard;

        private InputTypes inputTypeToUse;

        private bool keyPressed;

        public EntryWithCustomKeyboardRenderer(Context context) : base(context)
        {
            this.context = context;
        }

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

            var newCustomEntryKeyboard = e.NewElement as EntryWithCustomKeyboard;
            var oldCustomEntryKeyboard = e.OldElement as EntryWithCustomKeyboard;

            if (newCustomEntryKeyboard == null && oldCustomEntryKeyboard == null)
                return;

            if (e.NewElement != null)
            {
                this.entryWithCustomKeyboard = newCustomEntryKeyboard;
                this.CreateCustomKeyboard();

                this.inputTypeToUse = this.entryWithCustomKeyboard.Keyboard.ToInputType() | InputTypes.TextFlagNoSuggestions;
                
                // Here we set the EditText event handlers
                this.EditText.FocusChange += Control_FocusChange;
                this.EditText.TextChanged += EditText_TextChanged;
                this.EditText.Click += EditText_Click;
                this.EditText.Touch += EditText_Touch;

                #region BorderEntry
                var view = (EntryWithCustomKeyboard)Element;
                if (view.IsCurvedCornersEnabled)
                {
                    // creating gradient drawable for the curved background  
                    var _gradientBackground = new GradientDrawable();
                    _gradientBackground.SetShape(ShapeType.Rectangle);
                    _gradientBackground.SetColor(view.BackgroundColor.ToAndroid());

                    // Thickness of the stroke line  
                    _gradientBackground.SetStroke(view.BorderWidth, view.BorderColor.ToAndroid());

                    // Radius for the curves  
                    _gradientBackground.SetCornerRadius(
                        DpToPixels(this.Context, Convert.ToSingle(view.CornerRadius)));

                    // set the background of the   
                    Control.SetBackground(_gradientBackground);
                }
                // Set padding for the internal text from border  
                Control.SetPadding(
                    (int)DpToPixels(this.Context, Convert.ToSingle(12)), Control.PaddingTop,
                    (int)DpToPixels(this.Context, Convert.ToSingle(12)), Control.PaddingBottom);
                #endregion
            }

            // Dispose control
            if (e.OldElement != null)
            {
                this.EditText.FocusChange -= Control_FocusChange;
                this.EditText.TextChanged -= EditText_TextChanged;
                this.EditText.Click -= EditText_Click;
                this.EditText.Touch -= EditText_Touch;
            }
        }

        public static float DpToPixels(Context context, float valueInDp)
        {
            DisplayMetrics metrics = context.Resources.DisplayMetrics;
            return TypedValue.ApplyDimension(ComplexUnitType.Dip, valueInDp, metrics);
        }
        protected override void OnFocusChangeRequested(object sender, VisualElement.FocusRequestArgs e)
        {
            e.Result = true;

            if (e.Focus)
                this.Control.RequestFocus();
            else
                this.Control.ClearFocus();
        }

        #region EditText event handlers

        private void Control_FocusChange(object sender, FocusChangeEventArgs e)
        {
            // Workaround to avoid null reference exceptions in runtime
            if (this.EditText.Text == null)
                this.EditText.Text = string.Empty;

            if (e.HasFocus)
            {
                this.mKeyboardView.OnKeyboardActionListener = this;
                if (this.Element.Keyboard == Keyboard.Numeric)
                    this.CreateCustomKeyboard();

                this.ShowKeyboardWithAnimation();
            }
            else
            {
                // When the control looses focus, we set an empty listener to avoid crashes
                this.mKeyboardView.OnKeyboardActionListener = new NullListener();

                this.HideKeyboardView();
            }
        }

        private void EditText_TextChanged(object sender, Android.Text.TextChangedEventArgs e)
        {
            // Ensure no key is pressed to clear focus
            if (this.EditText.Text.Length != 0 && !this.keyPressed)
            {
                this.EditText.ClearFocus();
                return;
            }
        }

        private void EditText_Click(object sender, System.EventArgs e)
        {
            ShowKeyboardWithAnimation();
        }

        private void EditText_Touch(object sender, TouchEventArgs e)
        {
            this.EditText.InputType = InputTypes.Null;

            this.EditText.OnTouchEvent(e.Event);

            this.EditText.InputType = this.inputTypeToUse;

            e.Handled = true;
        }

        #endregion

        #region keyboard related

        private void CreateCustomKeyboard()
        {
            var context = CrossCurrentActivity.Current.Activity;
            var activity = context;

            var rootView = activity.Window.DecorView.FindViewById(Android.Resource.Id.Content);
            activity.Window.SetSoftInputMode(SoftInput.StateVisible);
            var activityRootView = (ViewGroup)((ViewGroup)rootView).GetChildAt(0);

            this.mKeyboardView = activityRootView.FindViewById<Android.InputMethodServices.KeyboardView>(Resource.Id.customKeyboard);

            // If the previous line fails, it means the keyboard needs to be created and added
            if (this.mKeyboardView == null)
            {
                this.mKeyboardView = (Android.InputMethodServices.KeyboardView)activity.LayoutInflater.Inflate(Resource.Layout.CustomKeyboard, null);
                this.mKeyboardView.Id = Resource.Id.customKeyboard;
                this.mKeyboardView.Focusable = true;
                this.mKeyboardView.FocusableInTouchMode = true;
                this.mKeyboardView.Release += (sender, e) => { };
                var layoutParams = new Android.Widget.RelativeLayout.LayoutParams(LayoutParams.WrapContent, LayoutParams.WrapContent);
                layoutParams.AddRule(LayoutRules.AlignParentBottom);
                activityRootView.AddView(this.mKeyboardView, layoutParams);
            }

            this.HideKeyboardView();

            this.mKeyboard = new Android.InputMethodServices.Keyboard(this.context, Resource.Xml.special_keyboard);

            this.SetCurrentKeyboard();
        }

        private void SetCurrentKeyboard()
        {
            this.mKeyboardView.Keyboard = this.mKeyboard;
        }

        // Method to show our custom keyboard
        private void ShowKeyboardWithAnimation()
        {
            // First we must ensure that custom keyboard is hidden to
            // prevent showing it multiple times
            if (this.mKeyboardView.Visibility == ViewStates.Gone)
            {
                // Ensure native keyboard is hidden
                var imm = (InputMethodManager)this.context.GetSystemService(Context.InputMethodService);
                imm.HideSoftInputFromWindow(this.EditText.WindowToken, 0);
                this.EditText.InputType = InputTypes.Null;

                var animation = AnimationUtils.LoadAnimation(this.context, Resource.Animation.slide_in_bottom);
                this.mKeyboardView.Animation = animation;

                this.mKeyboardView.Enabled = true;
                // Show custom keyboard with animation
                this.mKeyboardView.Visibility = ViewStates.Visible;
            }
        }

        // Method to hide our custom keyboard
        private void HideKeyboardView()
        {
            this.mKeyboardView.Visibility = ViewStates.Gone;
            this.mKeyboardView.Enabled = false;

            this.EditText.InputType = InputTypes.Null;
        }

        #endregion

        #region IOnKeyboardActionListener
        // Implementing IOnKeyboardActionListener interface
        public void OnKey([GeneratedEnum] Keycode primaryCode, [GeneratedEnum] Keycode[] keyCodes)
        {
            if (!this.EditText.IsFocused)
                return;

            // Ensure key is pressed to avoid removing focus
            this.keyPressed = true;

            // Create event for key press
            long eventTime = JavaSystem.CurrentTimeMillis();

            var ev = new KeyEvent(eventTime, eventTime, KeyEventActions.Down, primaryCode, 0, 0, 0, 0,
                                  KeyEventFlags.SoftKeyboard | KeyEventFlags.KeepTouchMode);

            // Ensure native keyboard is hidden
            var imm = (InputMethodManager)this.context.GetSystemService(Context.InputMethodService);
            imm.HideSoftInputFromWindow(this.EditText.WindowToken, HideSoftInputFlags.None);
            this.EditText.InputType = this.inputTypeToUse;

            const Keycode na = (Keycode)1000;
            const Keycode done = (Keycode)400;
            switch (ev.KeyCode)
            {
                case Keycode.Enter:
                    // Sometimes EditText takes long to update the HasFocus status
                    if (this.EditText.HasFocus)
                    {
                        // Close the keyboard, remove focus and launch command asociated action
                        this.HideKeyboardView();

                        this.ClearFocus();

                        this.entryWithCustomKeyboard.EnterCommand?.Execute(null);
                    }

                    break;
                case Keycode.NumpadDot:
                    if (!string.IsNullOrEmpty(EditText.Text))
                        EditText.Text += ".";
                    else
                        EditText.Text = ".";
                    break;
                case na:
                    EditText.Text = "N/A";
                    break;
                case done:
                    this.HideKeyboardView();

                    this.ClearFocus();
                    break;
                case Keycode.Del:
                    this.OnKeyLongPress(Keycode.Del, ev);
                    break;
            }

            // Set the cursor at the end of the text
            this.EditText.SetSelection(this.EditText.Text.Length);

            if (this.EditText.HasFocus)
            {
                this.DispatchKeyEvent(ev);

                this.keyPressed = false;
            }
        }

        public void OnPress([GeneratedEnum] Keycode primaryCode)
        {
        }

        public void OnRelease([GeneratedEnum] Keycode primaryCode)
        {
        }

        public void OnText(ICharSequence text)
        {
        }

        public void SwipeDown()
        {
        }

        public void SwipeLeft()
        {
        }

        public void SwipeRight()
        {
        }

        public void SwipeUp()
        {
        }
        #endregion


        private class NullListener : Java.Lang.Object, IOnKeyboardActionListener
        {
            public void OnKey([GeneratedEnum] Keycode primaryCode, [GeneratedEnum] Keycode[] keyCodes)
            {
            }

            public void OnPress([GeneratedEnum] Keycode primaryCode)
            {
            }

            public void OnRelease([GeneratedEnum] Keycode primaryCode)
            {
            }

            public void OnText(ICharSequence text)
            {
            }

            public void SwipeDown()
            {
            }

            public void SwipeLeft()
            {
            }

            public void SwipeRight()
            {
            }

            public void SwipeUp()
            {
            }
        }

    }

3- Layout For Keyboard-

<android.inputmethodservice.KeyboardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/keyboard"
    android:foregroundGravity="center"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:keyPreviewLayout="@null"
    android:keyBackground="@drawable/keyboard_background"
    android:textColor="@android:color/white"
    android:background="#E0E0E0" />

4- On XML folder for Designing Keys -

<?xml version="1.0" encoding="utf-8" ?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:keyWidth="8%p"
    android:keyHeight="50dp"
    android:horizontalGap="1%p"
    android:verticalGap="1%p">

    <Row android:keyHeight="4dp" android:rowEdgeFlags="top" android:verticalGap="1%p">
        <Key android:codes="0" android:keyWidth="100%p" android:keyIcon="@drawable/kb_separator_line" />
    </Row>
    <Row >
        <Key android:codes="0" android:keyWidth="0dp" android:horizontalGap="2%p" android:keyEdgeFlags="left" />
        <Key android:codes="8" android:keyLabel="1" android:keyWidth="18%p" />
        <Key android:codes="9" android:keyLabel="2" android:keyWidth="18%p" />
        <Key android:codes="10" android:keyLabel="3" android:keyWidth="18%p" />
        <Key android:codes="11" android:keyLabel="4" android:keyWidth="18%p" />
        <Key android:codes="12" android:keyLabel="5" android:keyWidth="18%p" />
        <Key android:codes="0" android:keyWidth="0dp" android:horizontalGap="2%p" android:keyEdgeFlags="right"  />
    </Row>
    <Row>
        <Key android:codes="0" android:keyWidth="0dp" android:horizontalGap="2%p" android:keyEdgeFlags="left" />
        <Key android:codes="13" android:keyLabel="6" android:keyWidth="18%p" />
        <Key android:codes="14" android:keyLabel="7" android:keyWidth="18%p" />
        <Key android:codes="15" android:keyLabel="8" android:keyWidth="18%p" />
        <Key android:codes="16" android:keyLabel="9" android:keyWidth="18%p" />
        <Key android:codes="7" android:keyLabel="0" android:keyWidth="18%p" />
        <Key android:codes="0" android:keyWidth="0dp" android:horizontalGap="2%p" android:keyEdgeFlags="right"  />
    </Row>
    <Row>
        <Key android:codes="0" android:keyWidth="0dp" android:horizontalGap="2%p" android:keyEdgeFlags="left" />
        <Key android:codes="1000" android:keyLabel="N/A" android:keyWidth="18%p" />
        <Key android:codes="67" android:keyWidth="18%p" android:isRepeatable="true"
             android:iconPreview="@drawable/sym_keyboard_delete" android:keyIcon="@drawable/sym_keyboard_delete"/>
        <Key android:codes="400" android:keyLabel="DONE" android:keyWidth="18%p" android:keyEdgeFlags="right"/>
        <Key android:codes="69" android:keyLabel="-" android:keyWidth="18%p" />
        <Key android:codes="158" android:keyLabel="." android:keyWidth="18%p" />
        <Key android:codes="0" android:keyWidth="0dp" android:horizontalGap="2%p" android:keyEdgeFlags="right"  />
    </Row>
</Keyboard>

5- Drawable Folder for Backgrounds -

<?xml version="1.0" encoding="utf-8" ?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:state_focused="false"
        android:state_selected="false"
        android:state_pressed="false"
        android:drawable="@drawable/normal" />
    <item
        android:state_pressed="true"
        android:drawable="@drawable/pressed" />
</selector>

a) For Normal State -

<?xml version="1.0" encoding="utf-8" ?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:left="2dp" android:right="2dp">
        <shape android:shape="rectangle">
            <solid android:color="#E0E0E0" />
        </shape>
    </item>

    <item android:bottom="2dp">
        <shape android:shape="rectangle">
            <solid android:color="#383838" />
        </shape>
    </item>
</layer-list>

b) For Pressed -

<?xml version="1.0" encoding="utf-8" ?> 
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#FAFAFA" />
</shape>

6- Animation -

<?xml version="1.0" encoding="utf-8" ?> 
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:fromYDelta="150%p" android:toYDelta="0" android:duration="200"/>
    <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="200" />
</set>

So, this is the whole code I have done for Custom Keyboard but it's not working as qit should be. Any help will be Ok. I am stuck in this for a long time please help.

标签: androidxamarin.formspopupwindowandroid-custom-keyboard

解决方案


推荐阅读