android – 在SpannableString中放大单个字符会影响行间距(仅限Marshmallow)

我有以下方法,它扩大了TextView中的第一个字符.

private void makeFirstLetterBig(TextView textView, String title) {
    final SpannableString spannableString = new SpannableString(title);
    int position = 0;
    spannableString.setSpan(new RelativeSizeSpan(2.0f), position, position + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    //textView.setText(spannableString.toString());
    textView.setText(spannableString, BufferType.SPANNABLE);
}

这是正在使用的TextView.

<TextView
    android:id="@+id/title_text_view"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="16sp"
    android:textColor="?attr/newsTitleTextViewSelector"
    android:duplicateParentState="true"
    android:text="TextView" />

这是Marshmallow 6之前的结果.

enter image description here

它看起来很漂亮,因为当文本内容包装到第二行时,大的第一个字符不会影响第二行.

但是,当在Marshmallow 6中运行相同的应用程序时,我得到以下结果.

enter image description here

看起来,大字“我”正在为整个文本内容创建一个大填充.这导致第二行(与亚马逊)与第一行有一个巨大的行间距.

我可以知道,我怎样才能在棉花糖6中避免这样的问题?我希望得到与棉花糖之前相同的结果.

p / s我也在https://code.google.com/p/android/issues/detail?id=191187提交了一份报告.

更新

2015年12月9日,Google已修复此问题,并将在Android 6.0.1 – https://code.google.com/p/android/issues/detail?id=191187中发布

解决方法:

TL; DR问题是由生成StaticLayout的方法中的错误引起的.

该bug与我最初的想法略有不同,它不会影响所有行,只会影响放大后的字符,如截图所示:

enter image description here

在Marshmallow中,添加了FontMetrics缓存以避免重新计算,如source code中的注释所述:

// measurement has to be done before performing line breaking
// but we don't want to recompute fontmetrics or span ranges the
// second time, so we cache those and then use those stored values

不幸的是,如果缓存中的fm.descent值低于之前的缓存值,则会丢弃该缓存中可用的fm.descent值,如snippet中所示:

for (int spanStart = paraStart, spanEnd; spanStart < paraEnd; spanStart = spanEnd) {
    // retrieve end of span
    spanEnd = spanEndCache[spanEndCacheIndex++];

    // retrieve cached metrics, order matches above
    fm.top = fmCache[fmCacheIndex * 4 + 0];
    fm.bottom = fmCache[fmCacheIndex * 4 + 1];
    fm.ascent = fmCache[fmCacheIndex * 4 + 2];
    fm.descent = fmCache[fmCacheIndex * 4 + 3];
    fmCacheIndex++;

    if (fm.top < fmTop) {
        fmTop = fm.top;
    }
    if (fm.ascent < fmAscent) {
        fmAscent = fm.ascent;
    }
    if (fm.descent > fmDescent) {
        fmDescent = fm.descent;
    }
    if (fm.bottom > fmBottom) {
        fmBottom = fm.bottom;
    }

    ....

一旦该值达到最大值,它将永远不会减少,这就是为什么每个后续行都有增加的行空间.

相关文章

Android性能优化——之控件的优化 前面讲了图像的优化,接下...
前言 上一篇已经讲了如何实现textView中粗字体效果,里面主要...
最近项目重构,涉及到了数据库和文件下载,发现GreenDao这个...
WebView加载页面的两种方式 一、加载网络页面 加载网络页面,...
给APP全局设置字体主要分为两个方面来介绍 一、给原生界面设...
前言 最近UI大牛出了一版新的效果图,按照IOS的效果做的,页...