如何为自定义Android视图实现提取文本功能

8

背景

在Android中,自定义编辑器视图可以通过InputConnection从系统键盘接收文本。我已经成功地创建了这样的视图。然而,当设备处于横屏模式时,系统有时会选择显示一个提取的文本视图。当用户在此模式下输入时,提取的文本视图应该更新为与自定义视图中相同的文本。

我尚未实现提取的文本视图功能。(这里是我尝试过的一些方法。

我也没有找到任何清晰的文档或完整的示例来说明如何实现它。(以下是我阅读过的一些更好的内容:onetwothreefour。)

MCVE

我创建了最基本的自定义编辑器。下面的gif显示了其功能。它可以从键盘接收文本,但在横屏模式下不会更新提取的文本视图。因此,您必须关闭键盘才能看到更新后的文本。

enter image description here

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个回答

1
你可以使用 inputMethodManager.updateExtractedText(view, token, extractedText) 来实现。
这个方法的第一个参数很容易,你可以传递你的 CustomView 实例。最后一个参数也很简单,只需要创建一个 ExtractedText 并设置其字段即可。
ExtractedText extractedText = new ExtractedText();
extractedText.text = "sample text";

更困难的是传递正确的令牌。为了知道这个参数的正确值,您可以在MyInputConnection类中覆盖方法getExtractedText(ExtractedTextRequest request, int flags)(令牌存储在请求对象中)。
@Override
public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
        currentToken = request.token;
        return new ExtractedText();
}

我从这个方法中返回一个空的ExtractedText对象,以使视图处于活动状态(默认情况下文本看起来像提示)。
你可以在这里找到我的解决方案 https://github.com/ljarka/ExtractedText

Extracted text preview


密钥是令牌。我以为我可以忽略它并将其设为0,但实际上需要设置它。 - Suragch
关于我如何使用您的答案解决我的更大问题,请参见此答案 - Suragch

0

你可以直接移除提取的视图。我尝试过了,当键盘正在使用时,你的自定义视图是可见的。

@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);
}

在我的问题结束时,我还附有一篇回答的链接,说明如何禁用提取的文本。然而,我不想禁用它。我想学习如何使用它,因为在某些情况下键盘占用太多空间,文本无法清晰地显示。在这种情况下使用提取的文本视图会更好。 - Suragch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接