美文网首页Android开发Android知识
Android Oreo--Autosizing TextVie

Android Oreo--Autosizing TextVie

作者: 宛丘之上兮 | 来源:发表于2017-12-20 20:46 被阅读509次
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"
        android:autoSizeMinTextSize="20dp"
        android: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

相关文章

网友评论

    本文标题:Android Oreo--Autosizing TextVie

    本文链接:https://www.haomeiwen.com/subject/mncnwxtx.html