Android 自定义 view 连接输入法

View 的源码里面有一个方法名为: onCreateInputConnection , 通过该方法可使自定义 view 连接 inputMethod, 可以接受输入信息。该方法的解释如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* Create a new InputConnection for an InputMethod to interact
* with the view. The default implementation returns null, since it doesn't
* support input methods. You can override this to implement such support.
* This is only needed for views that take focus and text input.
*
* <p>When implementing this, you probably also want to implement
* {@link #onCheckIsTextEditor()} to indicate you will return a
* non-null InputConnection.</p>
*
* <p>Also, take good care to fill in the {@link android.view.inputmethod.EditorInfo}
* object correctly and in its entirety, so that the connected IME can rely
* on its values. For example, {@link android.view.inputmethod.EditorInfo#initialSelStart}
* and {@link android.view.inputmethod.EditorInfo#initialSelEnd} members
* must be filled in with the correct cursor position for IMEs to work correctly
* with your application.</p>
*
* @param outAttrs Fill in with attribute information about the connection.
*/
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
return null;
}

onCreateInputConnection 方法连接了 view 和 inputMethod,通过创建一个 InputConnection 来接受输入法的信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/**
* Created by hanks on 2017/2/16.
*/

public class KInputConnection extends BaseInputConnection {

public KInputConnection(View targetView, boolean fullEditor) {
super(targetView, fullEditor);
}

// 输入法的按键信息
@Override
public boolean sendKeyEvent(KeyEvent event) {
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_DEL:
if (event.getAction()== KeyEvent.ACTION_UP
&& onCommitTextListener != null) {
onCommitTextListener.onDeleteText();
}
break;
}
return super.sendKeyEvent(event);
}

// 输入法提交了一个 text
@Override
public boolean commitText(CharSequence text, int newCursorPosition) {
if (onCommitTextListener != null) {
onCommitTextListener.commitText(text, newCursorPosition);
}
return true;
}

private OnCommitTextListener onCommitTextListener;

public void setOnCommitTextListener(OnCommitTextListener onCommitTextListener) {
this.onCommitTextListener = onCommitTextListener;
}

public interface OnCommitTextListener {
boolean commitText(CharSequence text, int newCursorPosition);

void onDeleteText();
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
/**
* 支持输入法的 view
* Created by hanks on 2017/2/16.
*/

public class KInputView extends View {

private StringBuilder content = new StringBuilder();
private KInputConnection inputConnection;
private TextPaint paint;
private InputMethodManager inputMethodManager;

public KInputView(Context context) {
this(context, null);
}

public KInputView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}

private void init() {

// 设置可以接受到焦点
this.setFocusable(true);
this.setFocusableInTouchMode(true);

// 获取 InputMethodManager
inputMethodManager = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);

paint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.BLUE);
float textSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 14, getResources().getDisplayMetrics());
paint.setTextSize(textSize);
setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 弹出、关闭输入法
inputMethodManager.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
}
});
}

@Override
public InputConnection onCreateInputConnection(EditorInfo editorInfo) {
return getInputConnection(editorInfo);
}

@Override
protected void onDraw(Canvas canvas) {
// 使用 StaticLayout 来 draw
new StaticLayout(content, paint, getWidth(), Layout.Alignment.ALIGN_NORMAL, 1.5f, 0, false).draw(canvas);
}

private InputConnection getInputConnection(EditorInfo editorInfo) {
if (inputConnection != null) {
return inputConnection;
}
inputConnection = new KInputConnection(this, false);
inputConnection.setOnCommitTextListener(new KInputConnection.OnCommitTextListener() {
@Override
public boolean commitText(CharSequence text, int newCursorPosition) {
content.append(text);
invalidate();
return false;
}

@Override
public void onDeleteText() {
if (content.length() <= 0) {
return;
}
content.deleteCharAt(content.length() - 1);
invalidate();
}
});
return inputConnection;
}
}

效果图

自定义 View