问题
I've created a custom editor for vertical Mongolian text. The circled views show my my custom editor. They keyboards at the bottom are system keyboards.
When a system keyboard inputs text into it in landscape orientation, though, the keyboard will likely show an extracted text view rather than my custom editor view. The circled view below is the extracted text view (which is not getting updated by my custom editor).
I need to somehow send updates from my view to the input method manager. This is stated in the InputConnection documentation:
Editor authors: as a general rule, try to comply with the fields in request for how many chars to return, but if performance or convenience dictates otherwise, please feel free to do what is most appropriate for your case. Also, if the
GET_EXTRACTED_TEXT_MONITOR
flag is set, you should be callingInputMethodManager.updateExtractedText(View, int, ExtractedText)
whenever you callInputMethodManager.updateSelection(View, int, int, int, int)
.
I've been exploring the source code related to extracted text
- TextView
- Editor
- InputMethodManager
- InputMethodService
- BaseInputConnection
but I'm lost.
Here is the closest I've gotten. This is a method inside my custom editor.
private void reportExtractedText() {
// TODO we should be modifying this based on an ExtractedTextRequest
ExtractedText et = new ExtractedText();
final CharSequence content = getText();
final int length = content.length();
et.partialStartOffset = 0;
et.partialEndOffset = length;
et.startOffset = 0;
et.selectionStart = getSelectionStart();
et.selectionEnd = getSelectionEnd();
et.flags = 0;
et.text = content.subSequence(0, length);
// FIXME: should be returning this from the ExtractedTextRequest
int requestToken = 0;
InputMethodManager imm = (InputMethodManager) getContext()
.getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm == null) return;
imm.updateExtractedText(this, requestToken, et);
}
When I am inside my editor I don't have a reference to the ExtractedTextRequest
, which should be used to modify what I include in my extracted text update.
Here is another method inside my BaseInputConnection
subclass (slightly modified from here). I have access to the ExtractedTextRequest
but this is not where I am calling the updates from. It will cause the extracted text view to show the initial text correctly, but the updates still don't get applied. This method is called by the InputMethodService
and can also be called by custom input methods.
@Override
public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
if (request == null)
return null;
if ((flags & GET_EXTRACTED_TEXT_MONITOR) != 0)
mExtractedTextRequest = request; // mExtractedTextRequest currently doing nothing
Editable editable = getEditable();
if (editable == null) {
return null;
}
int selStart = Selection.getSelectionStart(editable);
int selEnd = Selection.getSelectionEnd(editable);
ExtractedText extract = new ExtractedText();
extract.flags = 0;
extract.partialStartOffset = -1;
extract.partialEndOffset = -1;
extract.selectionStart = selStart;
extract.selectionEnd = selEnd;
extract.startOffset = 0;
if ((request.flags & GET_TEXT_WITH_STYLES) != 0) {
extract.text = new SpannableString(editable);
} else {
extract.text = editable.toString();
}
return extract;
}
I added a more generic MCVE here.
回答1:
The key to updating the extracted text view is to set the ExtractedTextRequest
token. Without the token the updates don't take effect. Thanks to this answer for help with the token.
We can the token in the input connection's getExtractedText()
with request.token
and then add a method to the custom view to set it:
@Override
public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
if (request == null)
return null;
Editable editable = getEditable();
if (editable == null) {
return null;
}
// passing the token to the custom view here
mMongolEditText.setExtractedTextToken(request.token);
int selStart = Selection.getSelectionStart(editable);
int selEnd = Selection.getSelectionEnd(editable);
ExtractedText extract = new ExtractedText();
extract.flags = 0;
extract.partialStartOffset = -1;
extract.partialEndOffset = -1;
extract.selectionStart = selStart;
extract.selectionEnd = selEnd;
extract.startOffset = 0;
if ((request.flags & GET_TEXT_WITH_STYLES) != 0) {
extract.text = new SpannableString(editable);
} else {
extract.text = editable.toString();
}
return extract;
}
That allows me to use the token when I call InputMethodManager.updateExtractedText()
from within my custom view.
private int mExtractedTextRequestToken = 0;
void setExtractedTextToken(int token) {
mExtractedTextRequestToken = token;
}
private void reportExtractedText() {
int requestToken = mExtractedTextRequestToken;
ExtractedText et = new ExtractedText();
final CharSequence content = getText();
final int length = content.length();
et.partialStartOffset = -1;
et.partialEndOffset = -1;
et.startOffset = 0;
et.selectionStart = getSelectionStart();
et.selectionEnd = getSelectionEnd();
et.flags = 0;
et.text = content.subSequence(0, length);
InputMethodManager imm = (InputMethodManager) getContext()
.getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm == null) return;
imm.updateExtractedText(this, requestToken, et);
}
You can view my full code here:
- Custom view
- Input connection
来源:https://stackoverflow.com/questions/50829361/how-to-update-extracted-text-in-a-custom-editor-view