Выбор TextView с помощью Spannable и LinkMovementMethod
То, что я сделал до сих пор, - это просмотр списка текстовых просмотров, имеющих обычный текст и интерактивные пробелы:
![Item untouched]()
Нажав на диапазон, я открываю URL-адрес, щелкнув элемент "Вид вокруг" textView, приводит к спискуView OnItemClickListener
, перемещаясь к деталям, что прекрасно:
![Item touched outside the textView]()
Теперь проблема заключается в следующем:
![Item textView normal text 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);