如何在android中的多行编辑文本中更改光标位置? [英] How to change cursor position in a multiline edittext in android?

查看:46
本文介绍了如何在android中的多行编辑文本中更改光标位置?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,我已经阅读了有关此事的其他问题,但我正在尝试不同的方法.

First of all, I've read the other questions on the matter, but I'm trying something different.

我有一个带有以下 XML 的多行 EditText:

I have a multiline EditText with the XML below:

<EditText
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:textColor="@color/textBodyColor"
        android:id="@+id/editScriptET"
        android:isScrollContainer="true"
        android:scrollbars="vertical"
        android:textSize="@dimen/font20"
        android:hint="@string/details"
        android:fontFamily="@font/courier_prime"
        android:inputType="textMultiLine"
        />

我想要做的是在单击菜单项时将光标设置在一行的中心或一行的左侧(在该多行 EditText 中).因此,当我单击菜单项时,我希望光标移动到 EditText 中当前行的中心.当按下另一个菜单项时,我需要将光标移到当前行的左侧.(所有菜单项始终显示在工具栏上.)

What I want to do is to set the cursor in the center of a line or at the left of a line (in that multiline EditText), when clicking on a menu item. So, when I click on a menu item I want the cursor to move at the center of the current line in the EditText. When pressing on another menu item, I need the cursor to go to the left of the current line. (All the menu items are always shown on the toolbar.)

有没有办法做到这一点?

Is there a way to do that?

我尝试使用 scriptET.setGravity(Gravity.CENTER);(其中 scriptET 是对我的 EditText 的引用),但没有任何反应.

I tried with scriptET.setGravity(Gravity.CENTER); (where scriptET is the refference to my EditText), but nothing happens.

使用评论中收到的建议,我设法使用 Selection.moveToLeftEdge(scriptET.getText(), scriptET.getLayout()); 将光标设置在左侧.使用一些 Toasts 消息时,我注意到 getLayout() 方法给出 null,但单击时光标仍移动到当前行的左侧.

Using the advice recieved in the comments, I managed to set the cursor to the left with Selection.moveToLeftEdge(scriptET.getText(), scriptET.getLayout());. Using some Toasts messages I've noticed that getLayout() method gives null, yet the cursor is still moving to the left of the current line when clicking.

此外,当该行为空时,将光标移至逻辑"中心是不可能的,而我确实需要这样做.

Also, moving the cursor in the 'logical' center is not possible when the line is empty, and I would really need that to be possible.

非常感谢任何建议!

推荐答案

有一个 android.text.Selection 类允许您在 EditText 中移动光标:

There's a android.text.Selection class which allows you to move the cursor in an EditText:

要将光标移动到行的左侧,请使用 Selection.moveToLeftEdge(edt.getText(), edt.getLayout()).还有一种方法是将光标移动到当前行的右侧.

To move cursor to the left of the line, use Selection.moveToLeftEdge(edt.getText(), edt.getLayout()). There's also a method to move the cursor at the right of the current line.

将光标移动到线的中心有点复杂.首先,您必须确定线的中心"是什么意思.例如,如果我们有以下行:

Moving the cursor to the center of the line is a bit more complicated. First, you have to decide what you mean by the "center" of the line. For example if we have the following line:

WWWWWWWWWWWWWWWWWWWWWWWWllllllllllllllllllllllll

WWWWWWWWWWWWWWWWWWWWWWWWWlllllllllllllllllllllllll

由 25 个大写 Ws 和 25 个小写 Ls 组成.在这条线上,中心是在 Ws 和 Ls 的交界处(在 pos 25)还是在 Ws 块内的某个地方?我们称前者为逻辑"中心,后者为视觉"中心.

which is made of 25 uppercase Ws and 25 lowecase Ls. In this line, is the center at the junction of the Ws and the Ls (at pos 25) or is it somewhere within the Ws block? Let's call the former the "logical" center, and the latter the "visual" center.

这是将光标移动到逻辑中心的方法:

Here's a method to move the cursor to the the logical center:

public void moveToLogicalLineCenter(EditText edt) {
    Spannable text = edt.getText();
    Layout layout = edt.getLayout();

    // Find the index of the line that cursor is currently on.
    int pos = Selection.getSelectionStart(text);
    int line = layout.getLineForOffset(pos);

    // Find the start pos and end pos of that line.
    int lineStart = layout.getLineStart(line);
    int lineEnd = layout.getLineEnd(line);

    // Calculate center pos and set selection.
    int lineCenter = Math.round((lineEnd + lineStart) / 2f);
    Selection.setSelection(text, lineCenter);
}

这是将光标移动到视觉中心的方法:

And here's a method to move the cursor to the visual center:

public void moveToVisualLineCenter(EditText edt) {
    Spannable text = edt.getText();
    Layout layout = edt.getLayout();

    // Find the index of the line that cursor is currently on.
    int pos = Selection.getSelectionEnd(text);
    int line = layout.getLineForOffset(pos);

    // Find the start pos and end pos of that line, and its text.
    int lineStart = layout.getLineStart(line);
    int lineEnd = layout.getLineEnd(line);
    CharSequence lineText = text.subSequence(lineStart, lineEnd);

    // Measure substrings of the line text of increasing lengths until we find the closest
    // to the EditText's center position.
    int centerX = edt.getMeasuredWidth() / 2 - edt.getPaddingLeft();
    TextPaint paint = edt.getPaint();
    float lastWidth = 0;
    for (int i = 1; i < lineText.length(); i++) {
        float width = paint.measureText(lineText, 0, i);
        if (width >= centerX) {
            // We're past the visual center.
            if (centerX - lastWidth < width - centerX) {
                // Turns out the last pos was closest, not this one.
                edt.setSelection(lineStart + i - 1);
            } else {
                // This pos is closest to the center.
                edt.setSelection(lineStart + i);
            }
            return;
        }
        lastWidth = width;
    }

    if (lineText.length() != 0) {
        // Line doesn't reach center, select line end.
        edt.setSelection(lineEnd);
    }  // Otherwise, line was empty, start of the line is already selected.
}

该方法使用TextPaint对文本进行测量,找到最接近EditText视觉中心的位置.如果行没有到达中心,则光标移动到行尾.理想情况下,您希望在这里进行二进制搜索而不是线性搜索以快速找到最近的位置,因为 TextPaint.measureText 是一项潜在的昂贵操作.例如,如果您打算使用包含数千个字符的行,这可能是最好的.

This method uses TextPaint to measure the text to find the position closest to the visual center of the EditText. If line doesn't reach the center, the cursor goes to the end of the line. Ideally you would want to do a binary search instead of a linear search here to quickly find the closest position, because TextPaint.measureText is a potentially expensive operation. For example if you intend to have lines with thousands of characters, it would probably be best.

我希望这能回答您的问题,否则请发表评论.

I hope this answers your question, otherwise leave a comment.

这篇关于如何在android中的多行编辑文本中更改光标位置?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆