Можно ли выбрать TextView и содержать ссылки? - программирование
Подтвердить что ты не робот

Можно ли выбрать TextView и содержать ссылки?

У меня возникла проблема с TextView. Я могу сделать его доступным с помощью setTextIsSelectable(true), но когда я включаю ссылки, которые нужно щелкнуть через setMovementMethod(LinkMovementMethod.getInstance()), он больше не может быть выбран.

Обратите внимание: я не имею в виду, что ссылки на исходные ссылки можно кликать, а вместо того, чтобы делать текущие слова интерактивными, загружая TextView с помощью HTML-разметки, используя что-то вроде setText(Html.fromHtml("<a href='http://stackoverflow.com'>Hello World!</a>")).

4b9b3361

Ответ 1

Я понял это. Вам нужно подклассировать LinkMovementMethod и добавить поддержку для выбора текста. Очень жаль, что он не поддерживает его изначально. Я просто переопределял соответствующие методы, используя эквивалентные из исходный код для ArrowKeyMovementMethod. Я предполагаю, что одно из преимуществ Android - с открытым исходным кодом!

public class CustomMovementMethod extends LinkMovementMethod {
    @Override
    public boolean canSelectArbitrarily () {
        return true;
    }

    @Override
    public void initialize(TextView widget, Spannable text) {
        Selection.setSelection(text, text.length());
    }

    @Override
    public void onTakeFocus(TextView view, Spannable text, int dir) {
       if ((dir & (View.FOCUS_FORWARD | View.FOCUS_DOWN)) != 0) {
           if (view.getLayout() == null) {
               // This shouldn't be null, but do something sensible if it is.
               Selection.setSelection(text, text.length());
           }
       } else {
           Selection.setSelection(text, text.length());
       }
    }
}

Чтобы использовать его, просто создайте его прямо так:

textView.setMovementMethod(new CustomMovementMethod());

Ответ 2

Ответ на вопрос oakes вызывает двойное нажатие на textview

java.lang.IndexOutOfBoundsException: setSpan (-1 ... -1) starts before 0...

Я просмотрел реализацию onTouchEvent в LinkMovementMethod и обнаружил, что он удаляет выделение, когда textview не содержит ссылку. В этом случае выбор начинается с пустого значения и сбоя приложения, когда пользователь пытается его изменить.

...
if (link.length != 0) {
    if (action == MotionEvent.ACTION_UP) {
        link[0].onClick(widget);
    } else if (action == MotionEvent.ACTION_DOWN) {
        Selection.setSelection(buffer,
        buffer.getSpanStart(link[0]),
        buffer.getSpanEnd(link[0]));
    }
  return true;
} else {
  Selection.removeSelection(buffer);
}
...

Итак, я переопределяю метод onTouchEvent, и он отлично работает.

public class CustomMovementMethod extends LinkMovementMethod {
    @Override
    public boolean canSelectArbitrarily () {
        return true;
    }

    @Override
    public void initialize(TextView widget, Spannable text) {
        Selection.setSelection(text, text.length());
    }

    @Override
    public void onTakeFocus(TextView view, Spannable text, int dir) {
        if ((dir & (View.FOCUS_FORWARD | View.FOCUS_DOWN)) != 0) {
            if (view.getLayout() == null) {
                // This shouldn't be null, but do something sensible if it is.
                Selection.setSelection(text, text.length());
            }
        } else {
            Selection.setSelection(text, text.length());
        }
    }

    @Override
    public boolean onTouchEvent(TextView widget, Spannable buffer,
                                MotionEvent event) {
        int action = event.getAction();

        if (action == MotionEvent.ACTION_UP ||
                action == MotionEvent.ACTION_DOWN) {
            int x = (int) event.getX();
            int y = (int) event.getY();

            x -= widget.getTotalPaddingLeft();
            y -= widget.getTotalPaddingTop();

            x += widget.getScrollX();
            y += widget.getScrollY();

            Layout layout = widget.getLayout();
            int line = layout.getLineForVertical(y);
            int off = layout.getOffsetForHorizontal(line, x);

            ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);

            if (link.length != 0) {
                if (action == MotionEvent.ACTION_UP) {
                    link[0].onClick(widget);
                } else if (action == MotionEvent.ACTION_DOWN) {
                    Selection.setSelection(buffer,
                            buffer.getSpanStart(link[0]),
                            buffer.getSpanEnd(link[0]));
                }
                return true;
            }
        }

        return Touch.onTouchEvent(widget, buffer, event);
    }
}

Надеюсь, что это будет полезно для кого-то.

Ответ 3

LinkMovementMethod() не поддерживает выбор текста очень хорошо, даже мы можем выбрать текст, но после прокрутки текстового поля выбор будет потерян.

Лучшая реализация распространяется от ArrowKeyMovementMethod, которая очень хорошо поддерживает выбор текста.

Подробнее см. в здесь

Ответ 4

XML TextView не должен иметь никакой ссылки или каких-либо атрибутов, которые можно выбрать:

<TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>

Затем установите все программно, соблюдая следующий порядок:

textView.setText(Html.fromHtml(myHtml));
Linkify.addLinks(textView, Linkify.WEB_URLS);
textView.setTextIsSelectable(true); // API-11 and above
textView.setMovementMethod(LinkMovementMethod.getInstance());

Ответ 5

можно ли связать TextView с URL-адресом? У вас есть 10 TextView и 10 URL-адресов, поэтому просто написать код, который, если щелкнуть TextView [3], уволит намерение веб-браузера (или браузера) с URL [3]