Xamarin Android:自定义渲染器的自定义键盘问题 - 出现在控件下方、按键不可按下等 [英] Xamarin Android: Issues with Custom Keyboard Of Custom Renderer - Appears Underneath Controls, Keys Not Pressable, etc

查看:22
本文介绍了Xamarin Android:自定义渲染器的自定义键盘问题 - 出现在控件下方、按键不可按下等的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在创建一个具有自定义键盘的自定义控件.我遇到了几个问题.

我使用的是 Visual Studio Community 2019,我使用 Android_Accelerated_x86_Oreo (Android 8.1 API-27) 作为我的 Android 模拟器.

总而言之,

我需要为 Entry 设置不同的样式,因此我从中创建了一个派生类,称为 TextBoxEntry.

我以编程方式在 MainPage.cs 中创建了所有控件,因此 MainPage.xaml 是空白的(好吧,几乎).

Android 特定代码,即渲染器,被塞进 MainActivity.cs.

最后,自定义键盘在 Resources/xml/keyboard.xml 下定义.

我无法解决这些问题(解决了 5 个中的 3 个):

  1. 为什么自定义渲染器的自定义键盘会出现在控件下方?

  2. 当键盘出现时,我需要获取它的高度,以便我可以相应地修改滚动视图尺寸.不幸的是,在 ControlOnFocusChanged() [EditText.FocusChange 事件处理程序] 中这样做是行不通的,因为在那个时间点,键盘仍未显示,因此,它的高度为 0.或者我应该在其他一些事件?应该改用 ViewTreeObserver.IOnGlobalLayoutListener.

  3. 键盘上的按键不可按下.有时,键盘会隐藏起来.我想当我按下键时,实际的条目会失去焦点.无论如何,我到底哪里出错了?

  4. 滚动视图的最后一列以及最后一行的 TextBoxEntries 被剪掉了.再次,我无法弄清楚出了什么问题.这可以通过将 Margin 设置为 1 来解决.

  5. 在ControlOnFocusChange()里面,a_height是1280,b_height是342.scrollview占据了整个屏幕的一半以上,但是它的高度远不是整个屏幕的一半.这两个以不同的单位显示吗?根据

    您可以从 GitHub 下载源文件.https://github.com/WendyZang/CustomKeyboardXamarinForms

    I am creating a custom control that has a custom keyboard. I have faced several issues.

    I am using Visual Studio Community 2019, and I'm using Android_Accelerated_x86_Oreo (Android 8.1 API-27) as my Android emulator.

    In summary,

    I need to style Entry differently, hence I create a derived class from it, called TextBoxEntry.

    I create all the controls programmatically, in MainPage.cs, hence, MainPage.xaml is blank (well, almost).

    Android specific codes, namely the renderer, are crammed into MainActivity.cs.

    And lastly, the custom keyboard, is defined under Resources/xml/keyboard.xml.

    I have not been able to work out these issues (3 of 5 solved):

    1. Why does the custom keyboard of the custom renderer appear underneath the controls?

    2. When the keyboard appears, I need to get its height, so that I could modify the scrollview dimension accordingly. Unfortunately, doing this inside ControlOnFocusChanged() [EditText.FocusChange event handler] just doesn't work, because at that point in time, the keyboard still isn't displayed yet, hence, its height is 0. Or should I do it in some other event? Should use ViewTreeObserver.IOnGlobalLayoutListener instead.

    3. The keys in the keyboard are not pressable. Sometimes, the keyboard goes into hiding. I guess when I press the keys, the actual entry loses focus. Anyway, where do I actually go wrong?

    4. The last column of the scrollview, as well as the the last row, have their TextBoxEntries clipped off. Again, I couldn't figure out what goes wrong. THIS IS SOLVED BY SETTING MARGIN TO 1.

    5. Inside ControlOnFocusChange(), a_height gives 1280, while b_height gives 342. The scrollview takes more than half of the entire screen, but its height is far from half of the entire screen. Are these two shown in different units? According to Find our the default height of the controls in Xamarin Forms, it seems that both Heights use different units... OK, this can be solved by some conversion.

    So, here is all the relevant files' content:

    MainPage.xaml:

    <?xml version="1.0" encoding="utf-8" ?>
    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 x:Class="CustomKeyboard.MainPage"/>
    
    

    MainPage.xaml.cs:

    using Xamarin.Forms;
    
    namespace CustomKeyboard
    {
        public class TextBoxEntry : Entry
        {
            public ScrollView ScrollView { get; set; } = null; // So that I could easily get its reference and work on it...
        }
        public partial class MainPage : ContentPage
        {
            AbsoluteLayout layout = null;
            ScrollView scrollview = null;
            Grid grid = null;
    
            public MainPage()
            {
                InitializeComponent();
                BuildControls();
                BuildTextBoxes();
            }
            private void BuildControls()
            {
                layout = new AbsoluteLayout();
                scrollview = new ScrollView();
                grid = new Grid();
                layout.Children.Add(scrollview, new Rectangle(0.5d, 0d, 0.95d, 0.85d), AbsoluteLayoutFlags.All);
                scrollview.BackgroundColor = Color.Yellow;
                scrollview.Padding = 5;
                scrollview.Content = grid;
                Content = layout;
            }
            private void BuildTextBoxes()
            {
                for (var i = 0; i < 50; ++i)
                {
                    if (i % 5 == 0)
                    {
                        var l = new Label()
                        {
                            Text = (i / 5).ToString(),
                            HorizontalTextAlignment = TextAlignment.Center,
                            VerticalTextAlignment = TextAlignment.Center,
                        };
                        grid.Children.Add(l, 0, i / 5);
                    }
                    else
                    {
                        var r = i / 5;
                        var c = i % 5;
                        var e = new TextBoxEntry();
                        e.Margin = 1; // THIS SOLVES ISSUE 4
                        e.ScrollView = scrollview;
                        grid.Children.Add(e, c, r);
                    }
                }
            }
        }
    }
    
    

    MainActivity.cs:

    using Android.App;
    using Android.Content;
    using Android.Content.PM;
    using Android.Graphics;
    using Android.Graphics.Drawables;
    using Android.InputMethodServices;
    using Android.OS;
    using Android.Support.Design.Widget;
    using Android.Views;
    using Android.Widget;
    
    using Java.Lang;
    
    using System.Threading.Tasks;
    
    using Xamarin.Forms;
    using Xamarin.Forms.Platform.Android;
    using Xamarin.Essentials;
    
    using CustomKeyboard;
    using CustomKeyboard.Droid;
    
    [assembly: ExportRenderer(typeof(TextBoxEntry), typeof(TextBoxEntryRenderer))]
    
    namespace CustomKeyboard.Droid
    {
        [Activity(
            Label = "CustomKeyboard",
            Icon = "@mipmap/icon",
            Theme = "@style/MainTheme",
            MainLauncher = true,
            ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation
        )]
    
        public class MainActivity : FormsAppCompatActivity
        {
            internal static MainActivity Instance { get; private set; }
            protected override void OnCreate(Bundle savedInstanceState)
            {
                Instance = this;
    
                base.OnCreate(savedInstanceState);
    
                Xamarin.Essentials.Platform.Init(this, savedInstanceState);
                Forms.Init(this, savedInstanceState);
                LoadApplication(new App());
            }
        }
    
        public class TextBoxEntryRenderer : ViewRenderer<TextBoxEntry, TextInputLayout>
        {
            public KeyboardView mKeyboardView;
            ViewGroup activityRootView;
            protected EditText editText => Control.EditText;
    
            public TextBoxEntryRenderer(Context context) : base(context) { }
    
            protected override TextInputLayout CreateNativeControl()
            {
                #region Add keyboard
                var activity = MainActivity.Instance as Activity;
                activity.Window.SetSoftInputMode(SoftInput.StateAlwaysHidden);
    
                var rootView = activity.Window.DecorView.FindViewById(Android.Resource.Id.Content);
                activityRootView = ((ViewGroup)rootView).GetChildAt(0) as ViewGroup;
    
                mKeyboardView = new KeyboardView(MainActivity.Instance, null);
                mKeyboardView.PreviewEnabled = false; //Removes magnified key popups on key press
                mKeyboardView.Visibility = ViewStates.Gone;
                mKeyboardView.Keyboard = new Android.InputMethodServices.Keyboard(Context, Resource.Xml.keyboard);
                mKeyboardView.Key += (sender, e) =>
                {
                    long eventTime = JavaSystem.CurrentTimeMillis();
                    DispatchKeyEvent(new KeyEvent(eventTime, eventTime, KeyEventActions.Down, e.PrimaryCode, 0, 0, 0, 0, KeyEventFlags.SoftKeyboard | KeyEventFlags.KeepTouchMode));
    
                    Task.Delay(1);
                };
                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
    
                var _editText = new EditText(Context);
                _editText.SetTextColor(Android.Graphics.Color.Black);
                var textInputLayout = new TextInputLayout(Context);
                textInputLayout.AddView(_editText);
                return textInputLayout;
            }
            protected override void OnElementChanged(ElementChangedEventArgs<TextBoxEntry> e)
            {
                base.OnElementChanged(e);
                if (e.OldElement != null && Control != null) editText.FocusChange -= ControlOnFocusChange;
                if (e.NewElement != null)
                {
                    SetNativeControl(CreateNativeControl());
                    editText.ShowSoftInputOnFocus = false;
                    editText.FocusChange += ControlOnFocusChange;
                    editText.SetPadding(20, 0, 20, 0);
                    editText.SetTextSize(Android.Util.ComplexUnitType.Px, 32);
                    editText.TextChanged += (source, args) => { };
                }
                if (Control != null)
                {
                    GradientDrawable gd = new GradientDrawable();
                    gd.SetColor(Android.Graphics.Color.Transparent);
                    Control.SetBackground(gd);
                    editText.Background = null; // Remove underline.
                    var shape = new ShapeDrawable(new Android.Graphics.Drawables.Shapes.RectShape());
                    shape.Paint.Color = Xamarin.Forms.Color.Gray.ToAndroid();
                    shape.Paint.SetStyle(Paint.Style.Stroke);
                    Control.Background = shape;
                }
            }
            private void ControlOnFocusChange(object sender, FocusChangeEventArgs args)
            {
                if (args.HasFocus)
                {
                    editText.Post(() =>
                    {
                        editText.RequestFocus();
                        if (mKeyboardView.Visibility == ViewStates.Gone) mKeyboardView.Visibility = ViewStates.Visible;
    
                        // Wanna resize scrollview, but couldn't get necessary info...!
                        var deviceDisplayInfo = DeviceDisplay.MainDisplayInfo;
                        var a_height = deviceDisplayInfo.Height;
                        var b_height = Element.ScrollView.Height;
                        var c_height = mKeyboardView.Height;
                    });
                }
                else
                {
                    // Hide keyboard
                    mKeyboardView.Visibility = ViewStates.Gone;
                }
            }
        }
    }
    
    

    And lastly, Resources/xml/keyboard.xml:

    <Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
        android:keyWidth="25%p" android:horizontalGap="0px"
        android:verticalGap="0px" android:keyHeight="27dip">
    
      <Row>
        <Key android:codes="8"  android:keyLabel="1" android:keyHeight="54dip" android:keyEdgeFlags="left" />
        <Key android:codes="9"  android:keyLabel="2" android:keyHeight="54dip" />
        <Key android:codes="10" android:keyLabel="3" android:keyHeight="54dip" />
        <Key android:codes="81" android:keyLabel="+" android:keyHeight="81dip" android:keyEdgeFlags="right" />
      </Row>
      <Row></Row>
      <Row>
        <Key android:codes="11" android:keyLabel="4" android:keyHeight="54dip" android:keyEdgeFlags="left" />
        <Key android:codes="12" android:keyLabel="5" android:keyHeight="54dip" />
        <Key android:codes="13" android:keyLabel="6" android:keyHeight="54dip" />
      </Row>
      <Row>
        <Key android:codes="66" android:keyLabel="RET" android:keyHeight="81dip" android:horizontalGap="75%p" android:keyEdgeFlags="right" />
      </Row>
      <Row>
        <Key android:codes="14" android:keyLabel="7" android:keyHeight="54dip" android:keyEdgeFlags="left" />
        <Key android:codes="15" android:keyLabel="8" android:keyHeight="54dip" />
        <Key android:codes="16" android:keyLabel="9" android:keyHeight="54dip" />
      </Row>
      <Row></Row>
      <Row>
        <Key android:codes="17" android:keyLabel="*" android:keyHeight="54dip" android:keyEdgeFlags="left" />
        <Key android:codes="7"  android:keyLabel="0" android:keyHeight="54dip" />
        <Key android:codes="18" android:keyLabel="#" android:keyHeight="54dip" />
        <Key android:codes="67" android:keyLabel="DEL" android:keyHeight="54dip" android:keyEdgeFlags="right" />
      </Row>
      <Row></Row>
    
    </Keyboard>
    

    解决方案

    Why does the custom keyboard of the custom renderer appear underneath the controls?

    Set the alignParentBottom property to true to make our keyboard to be visible from the bottom side of the screen.

    android:layout_alignParentBottom="true"
    

    The keys in the keyboard are not pressable. Sometimes, the keyboard goes into hiding. I guess when I press the keys, the actual entry loses focus. Anyway, where do I actually go wrong?

    Define a state selector for the two states our keys can have: normal (without pressing) and pressed with true or false.

    You could download the source file from the GitHub. https://github.com/WendyZang/CustomKeyboardXamarinForms

    这篇关于Xamarin Android:自定义渲染器的自定义键盘问题 - 出现在控件下方、按键不可按下等的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆