Android Oreo--Autosizing TextViews自适应TextView

topLogo.gif

The phantom menace

我在开发的时候遇到这样一个恶心的场景:一个TextView(本业务中是指horde_hall_name)的宽、高、字体大小(maxFontSize=20dp)都是固定的,但是文案不固定,文案短的话没问题,文案太长的话会显示不全。这给我造成了危机感(menace),我想到的解决方案是根据TextView的宽度来找到不大于maxFontSize的最大字号以保证文案能够完全显示,代码演示:

private void setHordeNameTextSize() {
    if (horde_hall_name_width <= 0 || mHordeEntity == null) {
        return;
    }
    int paddingLeftOrRight = ScreenUtil.dip2px(10);
    float maxTextSize = ScreenUtil.dp2px(this, 20);//最大20dp
    TextPaint tp = horde_hall_name.getPaint();
    if (tp.getTextSize() >= maxTextSize) {
        maxTextSize = getDesiredTextSize(horde_hall_name, mHordeEntity.name, horde_hall_name_width - 2 * paddingLeftOrRight, ScreenUtil.dp2px(this, 20), true);//最大20dp
    } else {
        maxTextSize = getDesiredTextSize(horde_hall_name, mHordeEntity.name, horde_hall_name_width - 2 * paddingLeftOrRight, ScreenUtil.dp2px(this, 20), false);//最大20dp
    }
    horde_hall_name.setTextSize(TypedValue.COMPLEX_UNIT_DIP, ScreenUtil.px2dip(maxTextSize));
    horde_hall_name.setText(mHordeEntity == null ? "" : mHordeEntity.name);
    LogUtil.i(TAG, "maxTextSize: " + maxTextSize);
}

private float getDesiredTextSize(TextView textView, String text, int maxWidth, int maxTextSize, boolean toSmall) {
    TextPaint tp = textView.getPaint();
    if (toSmall) {
        while (tp.measureText(text) > maxWidth) {
            tp.setTextSize(tp.getTextSize() - ScreenUtil.density);
            getDesiredTextSize(textView, text, maxWidth, maxTextSize, toSmall);
        }
        return tp.getTextSize() > maxTextSize ? maxTextSize : tp.getTextSize();
    } else {
        while (tp.measureText(text) < maxWidth - 10) {
            tp.setTextSize(tp.getTextSize() + ScreenUtil.density);
            getDesiredTextSize(textView, text, maxWidth, maxTextSize, toSmall);
        }
        return tp.getTextSize() > maxTextSize ? maxTextSize : tp.getTextSize();
    }
}

如果你是一个合格的androider,相信应该能看懂的。这样循环查找最优的字号性能很差,如果一个RecyclerView的每个item都用这种方式的话,估计页面会很卡,只适合单个TextView这样操作。

A New Hope

Android 8.0带来了a new hope,可以根据 TextView 的大小自动设置文本展开或收缩的大小。这意味着,在不同屏幕上优化文本大小或者优化包含动态内容的文本大小比以往简单多了。
API最终的目的是TextView能保证文本在字体大小阈值内占满控件的空间,如果文本达到了设置的字体范围的最大、最小值时,文本大小不会再继续变化。
API使用方式很简单,简单到只有一行代码呦:

<android.support.v7.widget.AppCompatTextView
        android:layout_width="180dp"
        android:layout_height="180dp"
        app:autoSizeTextType="uniform"/>

android:autoSizeTextType有两个值:取值none(默认,表示不自动缩放)、uniform(横、纵缩放)。
通过代码代码控制的话是这样写:

TextViewCompat . setAutoSizeTextTypeWithDefaults ( TextView textview , int autoSizeTextType )

至于该怎么缩放呢,autosizing textview有两种模式

  1. 粒度型(Granularity)
  2. 预置大小型(PresetSizes)

Granularity设置字体大小的最小值和最大值的变化范围,然后设置一个变化粒度值,TextView大小就不断增减变量该粒度值,在变化范围内均匀地动态缩放变化(你可以试下不设置最小值和最大值,我试了下,貌似有个默认的最小值,最大值貌似是无穷大)。代码演示:

<android.support.v7.widget.AppCompatTextView
        android:id="@+id/tv_autosize"
        android:layout_width="180dp"
        android:layout_height="180dp"
        app:autoSizeMinTextSize="20dp"
        app:autoSizeMaxTextSize="80dp"
        android:text="Hola, amigo"
        app:autoSizeStepGranularity="2dp"
        app:autoSizeTextType="uniform"/>

PresetSizes预置一个字体大小的数组,TextView从数组中选择合适的字体大小自动调整。
代码演示:

<android.support.v7.widget.AppCompatTextView
        android:id="@+id/tv_autosize"
        android:layout_width="180dp"
        android:layout_height="180dp"
        android:text="Hola, amigo"
        app:autoSizeStepGranularity="2dp"
        app:autoSizePresetSizes="@array/preset_sizes"
        app:autoSizeTextType="uniform"/>

<array name="preset_sizes">
        <item>12dp</item>
        <item>24dp</item>
        <item>36dp</item>
        <item>48dp</item>
        <item>60dp</item>
        <item>72dp</item>
        <item>84dp</item>
</array>

需要注意的是PresetSizes优先级比Granularity优先级高,如果两者同时设置,那么只有
PresetSizes会生效,为什么呢,我猜应该PresetSizes效率更高,毕竟是已经预置了字体大小呢!!
amigo,是不是很简单,很easy???

RETURN OF THE JEDI

有了android oreo提供的新的API,那么绝地归来,文章开头那个困扰我的问题也有了更优雅的解决方案了。
先举个简单的案例吧,此案例很简单,一个Checkbox控制采用Granularity模式Preset size模式;两个Button分别增大和减小TextView布局宽高,然后观察TextView的尺寸变化。代码演示:
xml代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:app="http://schemas.android.com/apk/res-auto"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical">

    <include layout="@layout/toolbar"/>

    <CheckBox
        android:id="@+id/ck_preset"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:checked="false"
        android:text="预置"/>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">

        <Button
            android:id="@+id/btn_plus"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="加大"/>
        <Button
            android:id="@+id/btn_minus"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="缩小"/>

    </LinearLayout>

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

        <android.support.v7.widget.AppCompatTextView
            android:id="@+id/autosize_textView"
            android:layout_width="60dp"
            android:layout_height="30dp"
            android:layout_gravity="center"
            app:android:autoSizeMinTextSize="20dp
            app:android:autoSizeMaxTextSize="80dp"
            android:background="@android:color/holo_red_dark"
            android:text="Hola, amigo"
            app:autoSizeStepGranularity="2dp"
            app:autoSizeTextType="uniform"/>

        <android.support.v7.widget.AppCompatTextView
            android:id="@+id/autosize_textView_preset_sizes"
            android:layout_width="60dp"
            android:layout_height="30dp"
            android:layout_gravity="center"
            android:layout_marginTop="5dp"
            android:background="@android:color/holo_blue_bright"
            android:text="Hola, amigo"
            app:autoSizePresetSizes="@array/preset_sizes"
            app:autoSizeTextType="uniform"/>

    </LinearLayout>

</LinearLayout>

kotlin代码:

    fun <T> lazyFast(operation: () -> T): Lazy<T> =   lazy(LazyThreadSafetyMode.NONE) {
        operation()
    }
    var mChangeStep = lazyFast {
        resources.displayMetrics.density * 2
    }
    lateinit var operateTextView: TextView
    private fun testAutoSizeTextView() {
        //ids: ck_preset   btn_plus   btn_minus   autosize_textView   autosize_textView_preset_sizes
        autosize_textView.visibility = if (ck_preset.isChecked) View.INVISIBLE else View.VISIBLE
        autosize_textView_preset_sizes.visibility = if (ck_preset.isChecked) View.VISIBLE else View.INVISIBLE
        operateTextView = autosize_textView
        ck_preset.setOnCheckedChangeListener { buttonView, isChecked ->
            autosize_textView.visibility = if (ck_preset.isChecked) View.INVISIBLE else View.VISIBLE
            autosize_textView_preset_sizes.visibility = if (ck_preset.isChecked) View.VISIBLE else View.INVISIBLE
            operateTextView = if (ck_preset.isChecked) autosize_textView_preset_sizes else autosize_textView
        }
        btn_plus.setOnClickListener {
            val ll = operateTextView.getLayoutParams()
            ll.width += mChangeStep.value.toInt()
            ll.height += mChangeStep.value.toInt()
            operateTextView.setLayoutParams(ll)
        }
        btn_minus.setOnClickListener {
            val ll = operateTextView.getLayoutParams()
            ll.width -= mChangeStep.value.toInt()
            ll.height -= mChangeStep.value.toInt()
            operateTextView.setLayoutParams(ll)
        }
    }

granularity的效果图:


[图片上传中...(presetSize.gif-feff7a-1513772665910-0)]

preset size效果图:


presetSize.gif




参考文献:

  1. https://developer.android.com/guide/topics/ui/look-and-feel/autosizing-textview.html
  2. http://blog.csdn.net/dale999/article/details/70145152?locationNum=9&fps=1

有错误的地方希望留言指正,我的邮箱:zhihui0727@gmail.com

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,016评论 4 62
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,378评论 25 707
  • 昨天买的芒果很好吃,早上做了芒果香蕉奶昔,吖米
    爱莎199阅读 199评论 0 0
  • 每天醒来,睡前,想得第一个人就是他,以前也是,但心情却混然不同,以前是甜蜜,而今,更多的是苦涩,我一次次的叮...
    奔跑的胖胖蜗牛阅读 565评论 0 0
  • 我总有一种隐隐约约的感觉,自身的某些缺陷随着一些紧急的事愈发凸显出来。喜欢拖延,喜欢把事情往后推,喜欢缓一缓再做事...
    遇见苏小州阅读 226评论 0 1