Я вставляю ImageSpans внутри TextViews, которые являются частью RecyclerView. В большинстве случаев он работает нормально, но при прокрутке вверх и вниз иногда высота TextView ошибочна без видимой причины - слишком много вертикальных пробелов.TextView с ImageSpans внутри RecyclerView = неправильный макет
В этом макете на определенном устройстве правильная высота для TextView с 1 строкой текста составляет 48, а неправильная высота - 80 (я получил эти значения из HierarchyViewer). Интересно, что правильная высота для TextView с 1 строкой текста, включая ImageSpan, равна 80. То, что, похоже, происходит, так как TextView получает переработку RecyclerView, иногда он сохраняет высоту, представляющую ее старый контент (который включает в себя ImageSpan).
На этом скриншоте показаны текстовые объекты «Anore» и «Halal blahs» размером 80 пикселей, что неверно. Текстовый текст «Hello» корректен при 48 пикселях.
При исследовании этого я открыл DDMS и побежал «дамп иерархии UI» и что-то интересное произошло: высота TextView исправил себя на лету:
Это довольно убедительные доказательства того, что проблема заключается в том, что TextView не корректно раскладывается после обновления текста, поэтому я пробовал различные способы вызова forceLayout() и invalidate() в TextView и его родительских представлениях, но это не помогло.
Я попытался заменить RecyclerView на ListView, не повезло. Я попробовал, чтобы все ImageSpans использовали один и тот же drawable, не повезло.
Я запускал HierarchyViewer, но он не «исправил» макеты, как это сделал UI Automator. Даже когда я нажал кнопки «invalidate layout» и «request layout».
Я не делаю ничего фантазии, чтобы установить ImageSpans:
SpannableStringBuilder stringBuilder = new SpannableStringBuilder(rawText);
for(int i = inlineImages.size() - 1; i >= 0; i--) {
InlineImage img = inlineImages.get(i);
stringBuilder.insert(img.idx, "x");
ImageSpan span = new ImageSpan(context, img.drawable);
stringBuilder.setSpan(span, img.idx, img.idx + 1, 0);
}
holder.mText.setText(stringBuilder);
// none of this helps
holder.mText.forceLayout();
holder.mText.requestLayout();
holder.mText.invalidate();
Вот соответствующая часть макета для каждого элемента списка:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/speech_bubble"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@drawable/speech_bubble_right"
android:layout_marginLeft="40dp"
>
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_toRightOf="@id/timestamp"
/>
</LinearLayout>
</RelativeLayout>
Я попытался недействительности и принуждать расположение на родитель TextView (LinearLayout), но он ничего не сделал.
Я попытался отредактировать макет вниз буквально следующее:
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
/>
.. и проблема все еще происходит. Это определенно вина самого TextView.
Что входит в TextView? У вас есть ссылка на эту ViewGroup? –
Отредактированный вопрос для включения макета списка. Я попытался сделать недействительным и вытеснить макет родителя, но ничего не сделал. – foo64
Вы можете временно удалить «LinearLayout» и посмотреть, каковы ваши результаты. Вы можете подклассифицировать «TextView», переопределить некоторые интересные методы (например, 'onMeasure()') и попытаться выяснить, что не вызвано, когда вы думаете, что это нужно. Вы можете попробовать вариант 'setText()', который принимает 'BufferType', хотя это не нужно. BTW, 'android: layout_toRightOf' для непосредственных детей« RelativeLayout », а не для детей« LinearLayout ». – CommonsWare