关闭

Android根据文字长度自动调整字号的TextView

标签: androidtextview
2241人阅读 评论(0) 收藏 举报
分类:

概述

在项目中遇到需求就是,标题根据文字的长度自动适配字号大小和换行显示,因为标题可能很长然后显示不完全。

实现

根据需求,很容易想到根据TextView的宽高和文字长度计算字号,然后重新设置TextView字号。


/**
* @author  Wastrel
* @date 创建时间:2016年8月19日 上午9:12:01
* TODO
*/

import android.content.Context;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Build;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.widget.TextView;

public class AutoFitTextView extends TextView {
    //unit px
    private static float DEFAULT_MIN_TEXT_SIZE = 15;
    private static float DEFAULT_MAX_TEXT_SIZE = 50;
    // Attributes
    private TextPaint testPaint;
    private float minTextSize;
    private float maxTextSize;

    public AutoFitTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initialise();
    }

    private void initialise() {
        testPaint = new TextPaint();
        testPaint.set(this.getPaint());
        // max size defaults to the intially specified text size unless it is too small
        maxTextSize = this.getTextSize();
        if (maxTextSize <= DEFAULT_MIN_TEXT_SIZE) {
            maxTextSize = DEFAULT_MAX_TEXT_SIZE;
        }
        minTextSize = DEFAULT_MIN_TEXT_SIZE;
    }

    /**
     * Re size the font so the specified text fits in the text box * assuming the text box is the specified width.
     */
    private void refitText(String text, int textWidth, int textHeight) {
        if (textWidth > 0&&textHeight>0) {
            //allow diplay rect
            int availableWidth = textWidth - this.getPaddingLeft() - this.getPaddingRight();
            int availableHeight = textHeight - this.getPaddingBottom() - this.getPaddingTop();
            //by the line calculate allow displayWidth
            int autoWidth = availableWidth;
            float mult=1f;
            float add=0;
            if (Build.VERSION.SDK_INT>16)
            {
                mult=getLineSpacingMultiplier();
                add=getLineSpacingExtra();
            }else{
                //the mult default is 1.0f,if you need change ,you can reflect invoke this field;
            }
            float trySize = maxTextSize;
            testPaint.setTextSize(trySize);
            int oldline=1,newline=1;
            while ((trySize > minTextSize)) {
                //calculate text singleline width。
                int displayW = (int) testPaint.measureText(text);
                //calculate text singleline height。
                int displaH=round(testPaint.getFontMetricsInt(null)*mult+add);
                if (displayW < autoWidth) {
                    break;
                }
                //calculate maxLines
                newline = availableHeight / displaH;
                //if line change ,calculate new autoWidth
                if (newline > oldline) {
                    oldline=newline;
                    autoWidth = availableWidth * newline;
                    continue;
                }
                //try more small TextSize
                trySize -= 1;
                if (trySize <= minTextSize) {
                    trySize = minTextSize;
                    break;
                }

                testPaint.setTextSize(trySize);
            }
            //setMultiLine
            if (newline>=2)
            {
                this.setSingleLine(false);
                this.setMaxLines(newline);
            }
            this.setTextSize(TypedValue.COMPLEX_UNIT_PX, trySize);
        }
    }

    @Override
    protected void onTextChanged(CharSequence text, int start, int before, int after) {
        super.onTextChanged(text, start, before, after);
        refitText(text.toString(), this.getWidth(), this.getHeight());
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        Log.e("TagSizeChange","new("+w+","+h+") old("+oldw+""+oldh+")");
        if (w != oldw || h != oldh) {
            refitText(this.getText().toString(), w, h);
        }
    }
    //FastMath.round()
     public static int round(float value) {
                long lx = (long) (value * (65536 * 256f));
                return (int) ((lx + 0x800000) >> 24);
            }
}

代码注释很详细,具体的请看代码。

效果

布局文件使用:

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

    <com.example.autofittext.AutoFitTextView
        android:background="#80808080"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:textSize="30sp"
        android:gravity="center"
        android:text="@string/str10" />
    <com.example.autofittext.AutoFitTextView
        android:layout_marginTop="15dp"
        android:background="#80808080"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:gravity="center"
        android:textSize="30sp"
        android:text="@string/str20"/>


    <com.example.autofittext.AutoFitTextView
        android:layout_marginTop="15dp"
        android:background="#80808080"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:gravity="center"
        android:textSize="30sp"
        android:text="@string/str30"/>

    <com.example.autofittext.AutoFitTextView
        android:layout_marginTop="15dp"
        android:background="#80808080"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:textSize="30sp"
        android:gravity="center"
        android:text="@string/str40"/>
    <com.example.autofittext.AutoFitTextView
        android:layout_marginTop="15dp"
        android:background="#80808080"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:gravity="center"
        android:textSize="30sp"
        android:text="@string/str50"/>
    <com.example.autofittext.AutoFitTextView
        android:layout_marginTop="15dp"
        android:background="#80808080"
        android:gravity="center"
        android:textSize="30sp"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:text="@string/str60"/>
    <com.example.autofittext.AutoFitTextView
        android:layout_marginTop="15dp"
        android:background="#80808080"
        android:gravity="center"
        android:textSize="30sp"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:text="@string/str70"/>
</LinearLayout>

效果图

后记

  • 使用的时候尽量对TextView的宽高限制。wrap_content 可能达不到想要的效果。
  • 如果想多行的时候左对齐,那么可以在设置多行的时候对Gravity 属性进行设置。
1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:43695次
    • 积分:666
    • 等级:
    • 排名:千里之外
    • 原创:18篇
    • 转载:1篇
    • 译文:1篇
    • 评论:17条
    文章分类
    最新评论