简体   繁体   中英

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

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

EDIT: 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.

Any suggestion is highly appreciated!

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

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:

WWWWWWWWWWWWWWWWWWWWWWWWWlllllllllllllllllllllllll

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

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.

just set TextAlignment attribute;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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