Выбор TextView с помощью Spannable и LinkMovementMethod

То, что я сделал до сих пор, - это просмотр списка текстовых просмотров, имеющих обычный текст и интерактивные пробелы: Item untouched

Нажав на диапазон, я открываю URL-адрес, щелкнув элемент "Вид вокруг" textView, приводит к спискуView OnItemClickListener, перемещаясь к деталям, что прекрасно: Item touched outside the textView

Теперь проблема заключается в следующем:

Item textView normal text touchedItem textView span touched  прикосновение к textView делает выделение обычного текста (с тем же цветом, что и при выборе элемента полностью), textView OnTouchListener срабатывает событие touch, но не OnFocusChangeListener, а элемент View не получает стиль выделения. Пробовал все варианты FOCUS_BLOCK_DESCENDANTS для listView, item View, textView focusable был включен или отключен с тем же результатом.

К счастью, событие textView OnClickListener срабатывает таким образом, но это настолько уродливо: текст невидим, пока сенсорный не выпущен, так как выделенный цвет текста совпадает с цветом элемента, нет другого указания, что пользователь переходя к деталям, кроме этого уродливого текста, исчезающего.

Я подозреваю, что это происходит, потому что содержимое textView Spannable, а части, которые не являются CliclableSpan-s, ведут себя странным образом.

Есть ли шанс, что я могу выбрать элемент, как только нормальный текст будет затронут?


Элемент списка listView:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:descendantFocusability="blocksDescendants"
    android:orientation="horizontal" >

    <ImageView
        android:id="@+id/icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_marginBottom="5dp"
        android:layout_marginLeft="5dp"
        android:layout_marginRight="5dp"
        android:layout_marginTop="5dp"
        android:focusable="false" />

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/title"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="5dp"
            android:layout_marginTop="5dp"
            android:focusable="false"
            android:text=""
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/info"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="4dp"
            android:layout_marginLeft="4dp"
            android:layout_marginRight="4dp"
            android:focusable="false"
            android:text=""
            android:textAppearance="?android:attr/textAppearanceSmall" />

        <TextView
            android:id="@+id/details"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="4dp"
            android:layout_marginLeft="4dp"
            android:layout_marginRight="4dp"
            android:focusable="false"
            android:gravity="fill_horizontal|right"
            android:text=""
            android:textAppearance="?android:attr/textAppearanceMedium"/>

    </LinearLayout>

</LinearLayout>

С текстовым представлением setClickable (false) я могу отключить этот странный стиль выделения таким образом, что ничего не происходит при касании области просмотра текста, но не полезно, но может быть полезно для решения.

Также попытался добавить не настраиваемую и не кликаемую кнопку для каждого элемента, когда он коснулся всего элемента, и когда прикосновение выпущено, событие события элемента передается, что именно то, что я ожидал от textView с содержимым Spannable.

Ответ 1

Вы пытались установить фон вашего TextView на Android по умолчанию list_selector_background?

    textView.setMovementMethod(LinkMovementMethod.getInstance());
    textView.setBackgroundResource(android.R.drawable.list_selector_background);

Для меня это, кажется, дает результат, который вы хотите.

ОБНОВЛЕНИЕ: увидев, что элемент является не только одним TextView

Ну, это не идеальное решение (поскольку, вероятно, лучше как-то исправлять взаимодействие с TextView - ListView), но он работает достаточно хорошо.

Я понял, что вместо того, чтобы устанавливать метод перемещения в TextView (который вызывает проблему), проще всего проверить ListView onItemClick() (после однозначного подтверждения щелчка), чтобы увидеть, нужно ли запускать onClick() на нашем ClickableSpans:

public class MyActivity extends Activity {

    private final Rect mLastTouch = new Rect();

    private boolean spanClicked(ListView list, View view, int textViewId) {
        final TextView widget = (TextView) view.findViewById(textViewId);
        list.offsetRectIntoDescendantCoords(widget, mLastTouch);
        int x = mLastTouch.right;
        int y = mLastTouch.bottom;

        x -= widget.getTotalPaddingLeft();
        y -= widget.getTotalPaddingTop();
        x += widget.getScrollX();
        y += widget.getScrollY();

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

        final Editable buffer = widget.getEditableText();
        final ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);

        if (link.length == 0) return false;

        link[0].onClick(widget);
        return true;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // ...

        listView.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                if (spanClicked(listView, view, R.id.details)) return;

                // no span is clicked, normal onItemClick handling code here ..                    
            }
        });
        listView.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_UP) {
                    mLastTouch.right = (int) event.getX();
                    mLastTouch.bottom = (int) event.getY();
                }
                return false;
            }
        });

        // ...
    }

}

Метод spanClicked() в основном представляет собой сокращенную версию метода LinkMovementMethod onTouchEvent() в рамках. Чтобы зафиксировать последние координаты MotionEvent (чтобы проверить событие щелчка), мы просто добавляем OnTouchListener в наш ListView.

Ответ 2

Я думаю, что лучший способ решить эту проблему - использовать селектор. вы можете выбрать цвет backgroun, чтобы они увидели то же самое

пример селекторного кода:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true"
       android:color="#000000" /> <!-- pressed -->
    <item android:state_focused="true"
       android:color="#000000" /> <!-- focused -->
    <item android:color="#FFFFFF" /> <!-- default -->
</selector>

реализуйте sth, как это, в вашу ссылку.

сообщите мне о результатах

Ответ 3

Цитата из документации setMovementMethod() of TextView

Устанавливает способ перемещения (стрелочный манипулятор), который будет использоваться для этого TextView. Это может быть null, чтобы запретить использование клавиш со стрелками для перемещения курсор или прокрутить представление.

Будьте предупреждены, что если вы хотите TextView с помощью метода прослушивания клавиш или движения, который не должен быть фокусируемым, или если вы хотите, чтобы TextView без прослушивателя клавиш или метода перемещения focusable, вы должны вызвать android.view.View.setFocusable(boolean) снова после вызова этого, чтобы получить фокусность обратно, как вы этого хотите.

Во втором абзаце объясняется, что мы должны явно вызвать метод setFocusable после установки LinkMovementMethod, чтобы получить фокусность, работающую так, как мы хотим.

Вам нужно сделать это в коде после раздувания элемента списка. Когда вы сможете получить фокус, вы можете установить селектор на другой цветной текст.

Вот исходный код setMovementMethod.

Ответ 4

Используйте TextView setHighlightColor(Color.TRANSPARENT);