在RecyclerView里面使用ImageSpans的TextView =错误的布局

时间:2015-03-14 03:18:15

标签: android android-layout textview spannablestring imagespan

我在ImageViews中插入ImageSpans,TextViews是RecyclerView的一部分。大部分时间它工作正常,但是当你向上和向下滚动时有时TextView高度是错误的,没有明显的原因 - 那里有太多的垂直空白。

在特定设备的此布局中,具有1行文本的TextView的正确高度为48,错误的高度为80(我从HierarchyViewer获取这些值)。有趣的是,包含ImageSpan在内的1行文本的TextView的正确高度为80.所以似乎正在发生的事情是TextView被RecyclerView回收,它有时会保持高度代表其旧内容(包括ImageSpan)。

此屏幕截图显示" Anore"和#34; Halal blahs" TextViews为80像素高,这是错误的。 "你好" TextView在48像素处是正确的。

Wrong height (80)

在调查这个问题时,我打开了DDMS并运行了"转储UI层次结构"并且发生了一些有趣的事情:TextView高度在飞行中自我纠正:

Correct height (48)

这个非常有说服力的证据证明问题是TextView在更新文本后没有正确布局,所以我尝试了各种方法在TextView及其父级上调用forceLayout()和invalidate()观点,但它没有帮助。

我尝试用ListView替换RecyclerView,没有运气。我试过让所有ImageSpans使用相同的drawable,没有运气。

我运行了HierarchyViewer,但它没有修复"像UI Automator这样的布局。甚至当我按下"无效布局"和"请求布局"的按钮。

我没有做任何想要设置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本身的错误。

2 个答案:

答案 0 :(得分:1)

我猜这里的问题不在于TextView的测量,而在于测量TextView的容器(一些ViewGroup - 也许是LinearLayout?)。

如果此ViewGroup的布局参数设置为WRAP_CONTENT高度,则由于某种原因,高度不会按时计算。要解决此问题,请尝试以下操作:

int widthMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY);
int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
holder.mContainer.measure(widthMeasureSpec, heightMeasureSpec); // perhaps a simple call to requestLayout or forceLayout will be enough?

如果您知道单元格的确切高度,也可以使用它 - 只需用以下内容替换我计算heightMeasureSpec的行:

int heightMeasureSpec = MeasureSpec.makeMeasureSpec(calculatedHeight + topPadding + bottomPadding, MeasureSpec.EXACTLY);

希望这有帮助。

答案 1 :(得分:0)

有点棘手

setTextSize(someDifferentSize);
setTextSize(normalSize);

似乎是某种线高问题,当图像跨度高于它时发生。如果我有时间,我会深入研究。