根据
文档,
View
(编辑器)通过
InputConnection
从键盘(IME)接收命令,并通过
InputMethodManager
向键盘发送命令。
![enter image description here](https://istack.dev59.com/tRMN1.webp)
我将在下面展示整个代码,但是这里有一些步骤。
1. 让键盘出现
由于视图正在向键盘发送命令,因此它需要使用一个 InputMethodManager
。为了方便起见,我们将假设当视图被点击时,它将显示键盘(如果已经显示则隐藏它)。
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, InputMethodManager.HIDE_IMPLICIT_ONLY);
}
return true;
}
视图还需要先调用
setFocusableInTouchMode(true)
。
2. 从键盘接收输入
为了让视图从键盘接收输入,它需要重写
onCreateInputConnection()
。这将返回键盘用于与视图通信的
InputConnection
。
@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
outAttrs.inputType = InputType.TYPE_CLASS_TEXT;
return new MyInputConnection(this, true);
}
outAttrs
指定视图请求的键盘类型。在这里,我们只是请求普通文本键盘。选择 TYPE_CLASS_NUMBER
将显示数字键盘(如果有)。还有许多其他选项。请参见 EditorInfo
。
您必须返回一个 InputConnection
,通常是 BaseInputConnection
的自定义子类。在该子类中,您提供对可编辑字符串的引用,键盘将对其进行更新。由于 SpannableStringBuilder
实现了 Editable
接口,因此我们将在基本示例中使用它。
public class MyInputConnection extends BaseInputConnection {
private SpannableStringBuilder mEditable;
MyInputConnection(View targetView, boolean fullEditor) {
super(targetView, fullEditor);
MyCustomView customView = (MyCustomView) targetView;
mEditable = customView.mText;
}
@Override
public Editable getEditable() {
return mEditable;
}
}
我们在这里所做的只是将输入连接与自定义视图中的文本变量BaseInputConnection
关联起来。这将由{{link1}}来处理编辑mText
。这可能就是你需要做的全部。然而,你可以查看源代码并查看哪些方法说“默认实现”,特别是“默认实现不执行任何操作”。这些都是你可能想要覆盖的其他方法,具体取决于你的编辑器视图的复杂程度。你还应该浏览文档中的所有方法名称。其中一些有针对“编辑器作者”的注释。请特别注意这些注释。
有些键盘出于某些原因(例如
删除、回车和一些
数字键),不会通过
InputConnection
发送某些输入。对于这些键,我添加了一个
OnKeyListener
。在五个不同的软键盘上测试这个设置,一切似乎都能正常工作。相关的补充答案在这里:
完整项目代码
以下是我完整的示例供参考。
![enter image description here](https://istack.dev59.com/Tg644.webp)
MyCustomView.java
public class MyCustomView extends View {
SpannableStringBuilder mText;
public MyCustomView(Context context) {
this(context, null, 0);
}
public MyCustomView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyCustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
setFocusableInTouchMode(true);
mText = new SpannableStringBuilder();
setOnKeyListener(new OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
if (event.getUnicodeChar() == 0) {
if (keyCode == KeyEvent.KEYCODE_DEL) {
mText.delete(mText.length() - 1, mText.length());
Log.i("TAG", "text: " + mText + " (keycode)");
return true;
}
} else {
mText.append((char)event.getUnicodeChar());
Log.i("TAG", "text: " + mText + " (keycode)");
return true;
}
}
return false;
}
});
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, InputMethodManager.HIDE_IMPLICIT_ONLY);
}
return true;
}
@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
outAttrs.inputType = InputType.TYPE_CLASS_TEXT;
return new MyInputConnection(this, true);
}
}
MyInputConnection.java
public class MyInputConnection extends BaseInputConnection {
private SpannableStringBuilder mEditable;
MyInputConnection(View targetView, boolean fullEditor) {
super(targetView, fullEditor);
MyCustomView customView = (MyCustomView) targetView;
mEditable = customView.mText;
}
@Override
public Editable getEditable() {
return mEditable;
}
@Override
public boolean commitText(CharSequence text, int newCursorPosition) {
boolean returnValue = super.commitText(text, newCursorPosition);
Log.i("TAG", "text: " + mEditable);
return returnValue;
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.editorview.MainActivity">
<com.example.editorview.MyCustomView
android:id="@+id/myCustomView"
android:background="@android:color/holo_blue_bright"
android:layout_margin="50dp"
android:layout_width="300dp"
android:layout_height="150dp"
android:layout_centerHorizontal="true"
/>
</RelativeLayout>
MainActivity.java代码中没有什么特别的。
如果这个方法对你不起作用,请留下评论。我正在制作一个自定义EditText的库,使用这种基本解决方案,如果有任何边缘情况无法正常工作,我想知道。如果您想查看该项目,自定义视图在这里。它的InputConnection
在这里。
相关信息