我正在制作一个自定义键盘,但是当我在我的设备上选择键盘时,它绘制在屏幕的顶部而不是底部,有效地阻止了我正在使用键盘写入的输入。
我试过在布局参数中设置重力以及 keyboar_layout.xml 文件中的相对布局。它拒绝在底部绘制。我一直在为我的键盘使用现在已经过时的 Keyboardview,并且工作正常。但是当我切换到使用 View.IOnTouchListener 时,这是它开始不在底部绘制的时候。在我的 oncreateview 中,我修复它的一些尝试被注释掉了,但无论哪种方式(如果它没有被注释掉)它仍然会绘制到屏幕顶部。
这里是keyboard_layout.xml:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentBottom="true"
android:background="@android:color/darker_gray"
android:orientation="vertical">
<TextView
android:id="@+id/myLabel"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Label text"
android:textColor="@android:color/white"
android:background="@android:color/black"
android:layout_marginTop="0.0dp" />
<NewKeyboard.CustomKeyboardView
android:id="@+id/keyboard"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@android:color/black"
android:layout_marginTop="0.0dp" />
</LinearLayout>
Here is the manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.yourcompanyname.NewKeyboard"
android:versionCode="1" android:versionName="1.0">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="33" />
<application android:label="NewKeyboard">
<service android:name=".MyInputMethodService"
android:permission="android.permission.BIND_INPUT_METHOD"
android:exported="true">
<intent-filter>
<action android:name="android.view.InputMethod" />
</intent-filter>
<meta-data android:name="android.view.im" android:resource="@xml/method" />
</service>
</application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</manifest>
Here is method.xml:
<input-method xmlns:android="http://schemas.android.com/apk/res/android">
<subtype
android:label="@string/subtype_en_US"
android:imeSubtypeLocale="en_US"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="AsciiCapable,EmojiCapable,SupportTouchPosition" />
</input-method>
CustomKeyboardview.cs:
using Android.Content;
using Android.Content.Res;
using Android.Graphics;
using Android.Runtime;
using Android.Util;
using Android.Views;
using Android.Views.InputMethods;
using Android.Widget;
using System;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Linq;
namespace NewKeyboard
{
public class Key
{
public int Code { get; set; }
public string Label { get; set; }
public RectF Rect { get; set; }
}
[Register("com.yourcompanyname.NewKeyboard.CustomKeyboardView")]
public class CustomKeyboardView : View, View.IOnTouchListener
{
private List<Key> keys;
private Paint keyPaint;
private Paint labelPaint;
public MyInputMethodService InputMethodService { get; set; }
public CustomKeyboardView(Context context) : base(context)
{
Initialize();
}
public CustomKeyboardView(Context context, IAttributeSet attrs) : base(context, attrs)
{
Initialize();
}
public CustomKeyboardView(Context context, IAttributeSet attrs, int defStyleAttr) : base(context, attrs, defStyleAttr)
{
Initialize();
}
public CustomKeyboardView(Context context, IAttributeSet attrs, int defStyleAttr, int defStyleRes) : base(context, attrs, defStyleAttr, defStyleRes)
{
Initialize();
}
protected CustomKeyboardView(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
{
}
private void Initialize()
{
// Create the keys from the context
keys = KeyboardLoader.CreateKeysList(Context);
// Initialize the Paint objects for drawing keys and labels
keyPaint = new Paint { Color = Color.LightGray };
labelPaint = new Paint { Color = Color.Black, TextSize = 40 };
// Set the OnTouchListener for this view
SetOnTouchListener(this);
}
protected override void OnDraw(Canvas canvas)
{
base.OnDraw(canvas);
// Draw the keys
foreach (var key in keys)
{
canvas.DrawRoundRect(key.Rect, 5, 5, keyPaint);
canvas.DrawText(key.Label, key.Rect.Left + key.Rect.Width() / 2 - labelPaint.MeasureText(key.Label) / 2, key.Rect.Top + key.Rect.Height() / 2 + labelPaint.TextSize / 2, labelPaint);
}
}
public bool OnTouch(View v, MotionEvent e)
{
if (e.Action == MotionEventActions.Down || e.Action == MotionEventActions.Move)
{
// Find the key that was touched
foreach (var key in keys)
{
if (key.Rect.Contains((int)e.GetX(), (int)e.GetY()))
{
// Trigger the appropriate key action
var ic = InputMethodService.CurrentInputConnection;
switch (key.Code)
{
case -1: // Shift
// Toggle caps and update the keyboard
break;
case -4: // Done
ic.SendKeyEvent(new KeyEvent(KeyEventActions.Down, Keycode.Enter));
break;
case -5: // Delete
ic.DeleteSurroundingText(1, 0);
break;
default:
char code = (char)key.Code;
ic.CommitText(code.ToString(), 1);
break;
}
break;
}
}
}
return true;
}
}
public static class KeyboardLoader
{
public static List<Key> CreateKeysList(Context context)
{
var keys = new List<Key>();
float keyWidth = 0.1f * Resources.System.DisplayMetrics.WidthPixels;
float keyHeight = TypedValue.ApplyDimension(ComplexUnitType.Dip, 60, context.Resources.DisplayMetrics);
float x = 0;
float y = 0;
int[][] keyCodes = new int[][]
{
new int[] { 49, 50, 51, 52, 53, 54, 55, 56, 57, 48 },
new int[] { 113, 119, 101, 114, 116, 121, 117, 105, 111, 112 },
new int[] { 97, 115, 100, 102, 103, 104, 106, 107, 108, -2 },
new int[] { -1, 122, 120, 99, 118, 98, 110, 109, 46, -3 },
new int[] { 44, 47, 32, -5, -4 }
};
string[][] keyLabels = new string[][]
{
new string[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "0" },
new string[] { "q", "w", "e", "r", "t", "y", "u", "i", "o", "p" },
new string[] { "a", "s", "d", "f", "g", "h", "j", "k", "l", "# @" },
new string[] { "CAPS", "z", "x", "c", "v", "b", "n", "m", ".", "? ! :" },
new string[] { ",", "/", "SPACE", "DEL", "DONE" }
};
for (int row = 0; row < keyCodes.Length; row++)
{
x = 0;
for (int col = 0; col < keyCodes[row].Length; col++)
{
var key = new Key
{
Code = keyCodes[row][col],
Label = keyLabels[row][col],
Rect = new RectF(x, y, x + keyWidth, y + keyHeight)
};
Console.WriteLine($"Creating key: Code: {key.Code}, Label: {key.Label}, Rect: {key.Rect}");
keys.Add(key);
x += keyWidth;
}
y += keyHeight;
}
return keys;
}
}
}
MainActivity.cs:
using Android.App;
using Android.OS;
using Android.Runtime;
using AndroidX.AppCompat.App;
namespace NewKeyboard
{
[Activity(Label = "@string/app_name", Theme = "@style/AppTheme", MainLauncher = true)]
public class MainActivity : AppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.HowToUse_layout);
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
}
And finally MyInputMethodService.cs:
using Android.Content;
using Android.InputMethodServices;
using Android.Runtime;
using Android.Views;
using Android.Views.InputMethods;
using Android.Widget;
using Keycode = Android.Views.Keycode;
namespace NewKeyboard
{
[Register("com.yourcompanyname.NewKeyboard.MyInputMethodService")]
public class MyInputMethodService : InputMethodService
{
private View layout;
private CustomKeyboardView keyboardView;
public override void OnComputeInsets(Insets outInsets)
{
base.OnComputeInsets(outInsets);
outInsets.ContentTopInsets = outInsets.VisibleTopInsets;
}
public override bool OnEvaluateFullscreenMode()
{
return false;
}
public override View OnCreateInputView()
{
layout = LayoutInflater.Inflate(Resource.Layout.keyboard_layout, null);
keyboardView = layout.FindViewById<CustomKeyboardView>(Resource.Id.keyboard);
keyboardView.InputMethodService = this;
//LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.WrapContent);
//layoutParams.Gravity = GravityFlags.Bottom;
//layout.LayoutParameters = layoutParams;
return layout;
}
public override View OnCreateCandidatesView()
{
// Return null if you don't need a candidates view
return null;
}
}
}