DSa*_*ire 2 android ime android-edittext
我正在写一个IME(InputMethodService),我在IME本身有一个编辑文本,但是当我想在编辑文本中输入文本时,编辑文本无法聚焦,我输入的内容只是转到外面的另一个编辑文本IME.如何使IME中的编辑文本像普通编辑文本一样工作
我解决这个问题的方法是保持两个输入连接,一个连接到用户正在编辑的原始文本字段,另一个连接到键盘内的文本字段.更多关于第二个.你应该已经拥有的第一个,它是键盘发送所有命令的地方.就我而言,它被称为mIC.所以我在我的类上创建了另一个名为mOtherIC的InputConnection变量,该变量具有InputConnection,并引入了一个名为getIC()的新方法,该方法只返回当时正在使用的两个InputConnections中的相应一个(在我的情况下由布尔值控制, true表示使用键盘中的文本字段,false表示使用最初显示键盘的文本字段.每次我以前访问过mIC时,我都用getIC()替换它,这样它就可以无缝地将输入发送到正确的输入连接.
键盘中文本字段的InputConnection在这里很有意思,我基本上必须将内部Android EditableInputConnection复制到我自己的CustomInputConnection类中:
public class CustomInputConnection extends BaseInputConnection {
private static final boolean DEBUG = false;
private static final String TAG = "CustomInputConnection";
private final TextView mTextView;
// Keeps track of nested begin/end batch edit to ensure this connection always has a
// balanced impact on its associated TextView.
// A negative value means that this connection has been finished by the InputMethodManager.
private int mBatchEditNesting;
public CustomInputConnection(TextView textview) {
super(textview, true);
mTextView = textview;
}
@Override
public Editable getEditable() {
TextView tv = mTextView;
if (tv != null) {
return tv.getEditableText();
}
return null;
}
@Override
public boolean beginBatchEdit() {
synchronized(this) {
if (mBatchEditNesting >= 0) {
mTextView.beginBatchEdit();
mBatchEditNesting++;
return true;
}
}
return false;
}
@Override
public boolean endBatchEdit() {
synchronized(this) {
if (mBatchEditNesting > 0) {
// When the connection is reset by the InputMethodManager and reportFinish
// is called, some endBatchEdit calls may still be asynchronously received from the
// IME. Do not take these into account, thus ensuring that this IC's final
// contribution to mTextView's nested batch edit count is zero.
mTextView.endBatchEdit();
mBatchEditNesting--;
return true;
}
}
return false;
}
// @Override
// protected void reportFinish() {
// super.reportFinish();
//
// synchronized(this) {
// while (mBatchEditNesting > 0) {
// endBatchEdit();
// }
// // Will prevent any further calls to begin or endBatchEdit
// mBatchEditNesting = -1;
// }
// }
@Override
public boolean clearMetaKeyStates(int states) {
final Editable content = getEditable();
if (content == null) return false;
KeyListener kl = mTextView.getKeyListener();
if (kl != null) {
try {
kl.clearMetaKeyState(mTextView, content, states);
} catch (AbstractMethodError e) {
// This is an old listener that doesn't implement the
// new method.
}
}
return true;
}
@Override
public boolean commitCompletion(CompletionInfo text) {
if (DEBUG) Log.v(TAG, "commitCompletion " + text);
mTextView.beginBatchEdit();
mTextView.onCommitCompletion(text);
mTextView.endBatchEdit();
return true;
}
/**
* Calls the {@link TextView#onCommitCorrection} method of the associated TextView.
*/
@Override
public boolean commitCorrection(CorrectionInfo correctionInfo) {
if (DEBUG) Log.v(TAG, "commitCorrection" + correctionInfo);
mTextView.beginBatchEdit();
mTextView.onCommitCorrection(correctionInfo);
mTextView.endBatchEdit();
return true;
}
@Override
public boolean performEditorAction(int actionCode) {
if (DEBUG) Log.v(TAG, "performEditorAction " + actionCode);
mTextView.onEditorAction(actionCode);
return true;
}
@Override
public boolean performContextMenuAction(int id) {
if (DEBUG) Log.v(TAG, "performContextMenuAction " + id);
mTextView.beginBatchEdit();
mTextView.onTextContextMenuItem(id);
mTextView.endBatchEdit();
return true;
}
@Override
public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
if (mTextView != null) {
ExtractedText et = new ExtractedText();
if (mTextView.extractText(request, et)) {
if ((flags&GET_EXTRACTED_TEXT_MONITOR) != 0) {
// mTextView.setExtracting(request);
}
return et;
}
}
return null;
}
@Override
public boolean performPrivateCommand(String action, Bundle data) {
mTextView.onPrivateIMECommand(action, data);
return true;
}
@Override
public boolean commitText(CharSequence text, int newCursorPosition) {
if (mTextView == null) {
return super.commitText(text, newCursorPosition);
}
if (text instanceof Spanned) {
Spanned spanned = ((Spanned) text);
SuggestionSpan[] spans = spanned.getSpans(0, text.length(), SuggestionSpan.class);
// mIMM.registerSuggestionSpansForNotification(spans);
}
// mTextView.resetErrorChangedFlag();
boolean success = super.commitText(text, newCursorPosition);
// mTextView.hideErrorIfUnchanged();
return success;
}
@Override
public boolean requestCursorUpdates(int cursorUpdateMode) {
if (DEBUG) Log.v(TAG, "requestUpdateCursorAnchorInfo " + cursorUpdateMode);
// It is possible that any other bit is used as a valid flag in a future release.
// We should reject the entire request in such a case.
final int KNOWN_FLAGS_MASK = InputConnection.CURSOR_UPDATE_IMMEDIATE |
InputConnection.CURSOR_UPDATE_MONITOR;
final int unknownFlags = cursorUpdateMode & ~KNOWN_FLAGS_MASK;
if (unknownFlags != 0) {
if (DEBUG) {
Log.d(TAG, "Rejecting requestUpdateCursorAnchorInfo due to unknown flags." +
" cursorUpdateMode=" + cursorUpdateMode +
" unknownFlags=" + unknownFlags);
}
return false;
}
return false;
// if (mIMM == null) {
// // In this case, TYPE_CURSOR_ANCHOR_INFO is not handled.
// // TODO: Return some notification code rather than false to indicate method that
// // CursorAnchorInfo is temporarily unavailable.
// return false;
// }
// mIMM.setUpdateCursorAnchorInfoMode(cursorUpdateMode);
// if ((cursorUpdateMode & InputConnection.CURSOR_UPDATE_IMMEDIATE) != 0) {
// if (mTextView == null) {
// // In this case, FLAG_CURSOR_ANCHOR_INFO_IMMEDIATE is silently ignored.
// // TODO: Return some notification code for the input method that indicates
// // FLAG_CURSOR_ANCHOR_INFO_IMMEDIATE is ignored.
// } else if (mTextView.isInLayout()) {
// // In this case, the view hierarchy is currently undergoing a layout pass.
// // IMM#updateCursorAnchorInfo is supposed to be called soon after the layout
// // pass is finished.
// } else {
// // This will schedule a layout pass of the view tree, and the layout event
// // eventually triggers IMM#updateCursorAnchorInfo.
// mTextView.requestLayout();
// }
// }
// return true;
}
}
Run Code Online (Sandbox Code Playgroud)
这个类看起来很糟糕,因为我注释掉了不能构建的代码,可能是因为它访问了内部的Android API.也就是说,有一些警告(当你切换到这个输入法时,可能需要手动设置光标,两个InputConnections之间的大写类型的结转),它可以工作.您现在要做的就是在某个时刻将mOtherIC从我的第一段设置为新的CustomInputConnection(yourTextfield),其中yourTextfield是键盘内的文本字段.
| 归档时间: |
|
| 查看次数: |
1377 次 |
| 最近记录: |