简体   繁体   English

如何在 android 的多行编辑文本中更改 cursor position?

[英]How to change cursor position in a multiline edittext in android?

First of all, I've read the other questions on the matter, but I'm trying something different.首先,我已经阅读了关于此事的其他问题,但我正在尝试不同的东西。

I have a multiline EditText with the XML below:我有一个多行 EditText,下面是 XML:

<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"
        />

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.我想要做的是在单击菜单项时将 cursor 设置在一行的中心或一行的左侧(在该多行 EditText 中)。 So, when I click on a menu item I want the cursor to move at the center of the current line in the EditText.因此,当我单击一个菜单项时,我希望 cursor 移动到 EditText 中当前行的中心。 When pressing on another menu item, I need the cursor to go to the left of the current line.当按下另一个菜单项时,我需要当前行左侧的 cursor 到 go。 (All the menu items are always shown on the toolbar.) (所有菜单项始终显示在工具栏上。)

Is there a way to do that?有没有办法做到这一点?

I tried with scriptET.setGravity(Gravity.CENTER);我试过scriptET.setGravity(Gravity.CENTER); (where scriptET is the refference to my EditText), but nothing happens. (其中scriptET是对我的 EditText 的引用),但没有任何反应。

EDIT: Using the advice recieved in the comments, I managed to set the cursor to the left with Selection.moveToLeftEdge(scriptET.getText(), scriptET.getLayout());编辑:使用评论中收到的建议,我设法将 cursor 设置在左侧,并使用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.使用一些 Toasts 消息,我注意到getLayout()方法给出了 null,但 cursor 在单击时仍然移动到当前行的左侧。

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.此外,当该行为空时,无法将 cursor 移动到“逻辑”中心,我真的需要这样做。

Any suggestion is highly appreciated!任何建议都非常感谢!

There's a android.text.Selection class which allows you to move the cursor in an EditText:有一个android.text.Selection class 允许您在 EditText 中移动 cursor:

To move cursor to the left of the line, use Selection.moveToLeftEdge(edt.getText(), edt.getLayout()) .要将 cursor 移动到行的左侧,请使用Selection.moveToLeftEdge(edt.getText(), edt.getLayout()) There's also a method to move the cursor at the right of the current line.还有一种方法可以移动当前行右侧的 cursor。

Moving the cursor to the center of the line is a bit more complicated.将 cursor 移动到线的中心有点复杂。 First, you have to decide what you mean by the "center" of the line.首先,您必须确定线条的“中心”是什么意思。 For example if we have the following line:例如,如果我们有以下行:

WWWWWWWWWWWWWWWWWWWWWWWWWlllllllllllllllllllllllll WWWWWWWWWWWWWWWWWWWWWWWWWllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll

which is made of 25 uppercase Ws and 25 lowecase Ls.它由 25 个大写的 Ws 和 25 个小写的 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?在这条线上,中心是在 Ws 和 Ls 的交界处(位置 25)还是在 Ws 块内的某个地方? 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:这是将 cursor 移动到逻辑中心的方法:

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:这是将 cursor 移动到视觉中心的方法:

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.
}

This method uses TextPaint to measure the text to find the position closest to the visual center of the EditText.该方法使用TextPaint对文本进行测量,找到距离EditText视觉中心最近的position。 If line doesn't reach the center, the cursor goes to the end of the line.如果线没有到达中心,cursor 会走到线的末端。 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.理想情况下,您希望在此处执行二进制搜索而不是线性搜索,以快速找到最接近的 position,因为TextPaint.measureText可能是一项昂贵的操作。 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.我希望这能回答您的问题,否则请发表评论。

just set TextAlignment attribute;只需设置 TextAlignment 属性;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM