Как реализовать извлеченный текст для пользовательского представления Android
Фон
Пользовательский вид редактора в Android может получать текст с системной клавиатуры через InputConnection
, Я был в состоянии сделать такой взгляд успешно. Однако, когда устройство находится в ландшафтном режиме, система иногда выбирает отображение извлеченного текстового представления. Когда пользователи вводят в этом режиме, извлеченное текстовое представление должно обновляться тем же текстом, что и в пользовательском представлении.
Я не был в состоянии реализовать извлеченную функциональность представления текста. ( Вот некоторые вещи, которые я пробовал.)
Я также не смог найти какой-либо четкой документации или полных примеров того, как это сделать. (Вот некоторые из лучших вещей, которые я прочитал: раз, два, три, четыре).
MCVE
Я создал самый простой пользовательский редактор, который я могу. Следующий рисунок показывает функциональность. Он может получать текст с клавиатуры, но не обновляет извлеченное текстовое представление в альбомной ориентации. Таким образом, вы не сможете увидеть обновленный текст, пока не отпустите клавиатуру.
MyCustomView.java
public class MyCustomView extends View {
SpannableStringBuilder mText;
Paint mPaint;
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();
mPaint = new Paint();
mPaint.setColor(Color.BLACK);
mPaint.setTextSize(60);
mPaint.setStyle(Paint.Style.FILL);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawText(mText, 0, mText.length(), 50, 100, mPaint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm == null) return false;
imm.showSoftInput(this, InputMethodManager.SHOW_FORCED);
}
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 MyCustomView customView;
MyInputConnection(View targetView, boolean fullEditor) {
super(targetView, fullEditor);
customView = (MyCustomView) targetView;
}
@Override
public Editable getEditable() {
return customView.mText;
}
@Override
public boolean commitText(CharSequence text, int newCursorPosition) {
boolean returnValue = super.commitText(text, newCursorPosition);
customView.invalidate();
return returnValue;
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<net.example.extractedtext.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>
Резюме
Я ищу канонический ответ, который описывает и дает пример того, как реализовать извлеченные текстовые обновления для пользовательского представления редактора.
Если я сам это выясню, я добавлю свой ответ. До этого момента лучшее, что мне удавалось сделать, это вообще отключить извлеченный текст. Это не идеально.
2 ответа
Ты можешь использовать inputMethodManager.updateExtractedText(view, token, extractedText)
для этого.
Первый параметр этого метода прост. Вы можете передать экземпляр вашего CustomView там. Последний тоже. Просто создайте ExtractedText и установите его поля следующим образом.
ExtractedText extractedText = new ExtractedText();
extractedText.text = "sample text";
Сложнее передать правильный токен. Чтобы узнать правильное значение этого параметра, вы можете переопределить методgetExtractedText(ExtractedTextRequest request, int flags)
внутри вашего класса MyInputConnection (токен хранится в объекте запроса).
@Override
public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
currentToken = request.token;
return new ExtractedText();
}
Я возвращаю пустой объект ExtractedText из этого метода, чтобы сделать представление активным (по умолчанию текст выглядит как подсказка).
Вы можете найти мое решение здесь https://github.com/ljarka/ExtractedText
Вы можете просто удалить извлеченный вид. Я попробовал это, и ваш пользовательский виден во время использования клавиатуры.
@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
outAttrs.inputType = InputType.TYPE_CLASS_TEXT;
//remove extract view
outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI;
return new MyInputConnection(this, true);
}