【问题标题】:How to change cursor position in a multiline edittext in android?如何在android的多行edittext中更改光标位置?
【发布时间】:2020-06-09 14:29:06
【问题描述】:

首先,我已经阅读了关于此事的其他问题,但我正在尝试不同的东西。

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

<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 中当前行的中心。当按下另一个菜单项时,我需要将光标移到当前行的左侧。 (所有菜单项始终显示在工具栏上。)

有没有办法做到这一点?

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

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

此外,当该行为空时,无法在“逻辑”中心移动光标,我真的需要这样做。

非常感谢任何建议!

【问题讨论】:

  • edittext 是空的还是填充的?
  • 一开始它是空的,但是使用光标的这些规则,它会被文本填充,其中的行应该是不同的对齐方式。

标签: java android android-edittext cursor-position


【解决方案1】:

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

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

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

WWWWWWWWWWWWWWWWWWWWWWWWwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww

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

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

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

还有一个将光标移动到视觉中心的方法:

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 是一个潜在的昂贵操作。例如,如果您打算有数千个字符的行,那可能是最好的。

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

【讨论】:

  • 谢谢你,我真的希望这会奏效,但它没有,我不明白为什么,甚至没有向左移动光标。我猜问题出在其他地方……
  • 当您调用选择方法时,您的 EditText 是否可能没有焦点?因为如果是这样的话,它就行不通了。尝试之前拨打edt.requestFocus()
  • 我把重点放在EditText上,谢谢。问题是如果没有填充文本,我不允许将光标移动到行的逻辑中心。即使该行是空的,我也想移动它。
  • 你不能轻易做到这一点。您必须在光标前插入空格。至于返回null的getLayout(),有时会出现这种情况,见stackoverflow.com/questions/16558948
【解决方案2】:

只需设置 TextAlignment 属性;

【讨论】:

    猜你喜欢
    • 2018-09-11
    • 2011-08-23
    • 2016-04-04
    • 2015-11-13
    • 1970-01-01
    • 1970-01-01
    • 2011-04-08
    • 2023-03-14
    • 1970-01-01
    相关资源
    最近更新 更多