如何调整文本字体大小以适应TextView?

187
有没有办法在Android中调整TextView的文本大小以适应其所占空间?例如,我正在使用TableLayout并在每行中添加多个TextView。由于不希望TextView换行,我希望看到它降低内容的字体大小。有什么好的想法吗?我尝试过measureText,但由于我不知道列的大小,使用起来似乎很麻烦。这是我想要改变字体大小以适应的代码。
TableRow row = new TableRow(this);   
for (int i=0; i < ColumnNames.length; i++) {    
    TextView textColumn = new TextView(this);      
    textColumn.setText(ColumnNames[i]);
    textColumn.setPadding(0, 0, 1, 0);
    textColumn.setTextColor(getResources().getColor(R.drawable.text_default));          
    row.addView(textColumn, new TableRow.LayoutParams()); 
} 
table.addView(row, new TableLayout.LayoutParams());  

请查看基于dunni代码的我的解决方案,链接在这里:https://dev59.com/iW445IYBdhLWcg3wGmk6#5280436 注意:我没有使用循环实现它。附言:感谢dunni。 - vsm
23个回答

133
下面的解决方案包含了所有这里提出的建议。它以Dunni最初发布的内容为基础。它使用了类似于gjpc的二分搜索,但更易读。它还包括了gregm的错误修复和我自己的错误修复。
import android.content.Context;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.TextView;

public class FontFitTextView extends TextView {

    public FontFitTextView(Context context) {
        super(context);
        initialise();
    }

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

    private void initialise() {
        mTestPaint = new Paint();
        mTestPaint.set(this.getPaint());
        //max size defaults to the initially specified text size unless it is too small
    }

    /* 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) 
    { 
        if (textWidth <= 0)
            return;
        int targetWidth = textWidth - this.getPaddingLeft() - this.getPaddingRight();
        float hi = 100;
        float lo = 2;
        final float threshold = 0.5f; // How close we have to be

        mTestPaint.set(this.getPaint());

        while((hi - lo) > threshold) {
            float size = (hi+lo)/2;
            mTestPaint.setTextSize(size);
            if(mTestPaint.measureText(text) >= targetWidth) 
                hi = size; // too big
            else
                lo = size; // too small
        }
        // Use lo so that we undershoot rather than overshoot
        this.setTextSize(TypedValue.COMPLEX_UNIT_PX, lo);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
        int height = getMeasuredHeight();
        refitText(this.getText().toString(), parentWidth);
        this.setMeasuredDimension(parentWidth, height);
    }

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

    @Override
    protected void onSizeChanged (int w, int h, int oldw, int oldh) {
        if (w != oldw) {
            refitText(this.getText().toString(), w);
        }
    }

    //Attributes
    private Paint mTestPaint;
}

9
谢谢您整合所有的反馈意见。我发现这个解决方案只考虑了宽度。我的问题是字体超过了高度。 - AlikElzin-kilaka
3
似乎在运行时部分有效。在设备或模拟器上,文本被截断了一半。在Eclipse布局编辑器中,它看起来很好。有什么想法吗? - AlikElzin-kilaka
7
这是一个很好的解决方案!如果有其他刚接触安卓开发并不太清楚如何在XML中实现扩展视图的人,可以像这样做:<com.example.zengame1.FontFitTextView android:paddingTop="5dip" android:id="@+id/childs_name" android:layout_width="fill_parent" android:layout_height="0dip" android:layout_weight="1" android:layout_gravity="center" android:textSize="@dimen/text_size"/> - Casey Murray
1
好的解决方案。如果您需要非常大的文本大小以适应非常大的屏幕,请增加“float hi”的初始值。 - Ricardo
2
干得好!还可以与按钮一起工作。为了处理TextView的高度,只需设置float hi = this.getHeight() - this.getPaddingBottom() - this.getPaddingTop();即可。 - AlexGuti
显示剩余12条评论

29

我写了一个扩展TextView的类来实现这个功能。它只是使用了您建议的measureText方法。基本上,它具有最大文本大小和最小文本大小(可以更改),并且只需以1的递减量运行它们之间的大小,直到找到适合的最大值。不是特别优雅,但我不知道还有其他方法。

以下是代码:

import android.content.Context;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.widget.TextView;

public class FontFitTextView extends TextView {

    public FontFitTextView(Context context) {
        super(context);
        initialise();
    }

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

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

    /* 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) { 
        if (textWidth > 0) {
            int availableWidth = textWidth - this.getPaddingLeft() - this.getPaddingRight();
            float trySize = maxTextSize;

            testPaint.setTextSize(trySize);
            while ((trySize > minTextSize) && (testPaint.measureText(text) > availableWidth)) {
                trySize -= 1;
                if (trySize <= minTextSize) {
                    trySize = minTextSize;
                    break;
                }
                testPaint.setTextSize(trySize);
            }

            this.setTextSize(trySize);
        }
    }

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

    @Override
    protected void onSizeChanged (int w, int h, int oldw, int oldh) {
        if (w != oldw) {
            refitText(this.getText().toString(), w);
        }
    }

    //Getters and Setters
    public float getMinTextSize() {
        return minTextSize;
    }

    public void setMinTextSize(int minTextSize) {
        this.minTextSize = minTextSize;
    }

    public float getMaxTextSize() {
        return maxTextSize;
    }

    public void setMaxTextSize(int minTextSize) {
        this.maxTextSize = minTextSize;
    }

    //Attributes
    private Paint testPaint;
    private float minTextSize;
    private float maxTextSize;

}

11
使用二分查找通常比线性查找更快。 - Ted Hopp
我认为在“onLayout”而不是“onSizeChanged”中进行refitText会更合理。 - LiangWang
你能否请看一下我的问题:http://stackoverflow.com/questions/36265448/objectanimator-pixlated-textview - Muhammad

18

这是speedplane的FontFitTextView,但它仅在需要时减小字体大小以使文本适合,并保持其字体大小。它不会增大字体大小以适应高度。

public class FontFitTextView extends TextView {

    // Attributes
    private Paint mTestPaint;
    private float defaultTextSize;

    public FontFitTextView(Context context) {
        super(context);
        initialize();
    }

    public FontFitTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initialize();
    }

    private void initialize() {
        mTestPaint = new Paint();
        mTestPaint.set(this.getPaint());
        defaultTextSize = getTextSize();
    }

    /* 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) {

        if (textWidth <= 0 || text.isEmpty())
            return;

        int targetWidth = textWidth - this.getPaddingLeft() - this.getPaddingRight();

        // this is most likely a non-relevant call
        if( targetWidth<=2 )
            return;

        // text already fits with the xml-defined font size?
        mTestPaint.set(this.getPaint());
        mTestPaint.setTextSize(defaultTextSize);
        if(mTestPaint.measureText(text) <= targetWidth) {
            this.setTextSize(TypedValue.COMPLEX_UNIT_PX, defaultTextSize);
            return;
        }

        // adjust text size using binary search for efficiency
        float hi = defaultTextSize;
        float lo = 2;
        final float threshold = 0.5f; // How close we have to be
        while (hi - lo > threshold) {
            float size = (hi + lo) / 2;
            mTestPaint.setTextSize(size);
            if(mTestPaint.measureText(text) >= targetWidth ) 
                hi = size; // too big
            else 
                lo = size; // too small

        }

        // Use lo so that we undershoot rather than overshoot
        this.setTextSize(TypedValue.COMPLEX_UNIT_PX, lo);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
        int height = getMeasuredHeight();
        refitText(this.getText().toString(), parentWidth);
        this.setMeasuredDimension(parentWidth, height);
    }

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

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        if (w != oldw || h != oldh) {
            refitText(this.getText().toString(), w);
        }
    }

}

这里是一个示例,它演示了如何在xml中使用:

<com.your.package.activity.widget.FontFitTextView
    android:id="@+id/my_id"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:text="My Text"
    android:textSize="60sp" />

只要文本适合宽度,这将保持字体大小为60sp。如果文本太长,它将减小字体大小。在这种情况下,TextView的高度也会因为 height=wrap_content而发生变化。

如果您发现任何错误,请随意进行编辑。


1
很好的输入,我纠正了代码 :) 现在它可以使用match_parentwrap_content - sulai
为什么你要测试空字符串写成"".equals(s),而不是简单地使用s.isEmpty()或者s.length()==0呢?我不明白为什么有时候会看到这些相等性测试。 - Zordid
很好的观点@Zordid,直到现在我才知道string.isEmpty() :) - sulai
text.isEmpty() Call requires API level 9 (current min is 8): java.lang.String#isEmpty change it to text.equals(null) - Pratik Butani
1
@PratikButani 感谢您指出这一点。text.isEmpty() 的等效方法是 "".equals(text) - sulai
显示剩余5条评论

14

这是我的解决方案,可在模拟器和手机上运行,但在Eclipse布局编辑器上效果不是很好。它受到kilaka代码的启发,但文本大小不是从Paint获取的,而是从调用measure(0, 0)来测量TextView本身的大小。

Java类:

public class FontFitTextView extends TextView
{
    private static final float THRESHOLD = 0.5f;

    private enum Mode { Width, Height, Both, None }

    private int minTextSize = 1;
    private int maxTextSize = 1000;

    private Mode mode = Mode.None;
    private boolean inComputation;
    private int widthMeasureSpec;
    private int heightMeasureSpec;

    public FontFitTextView(Context context) {
            super(context);
    }

    public FontFitTextView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
    }

    public FontFitTextView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);

            TypedArray tAttrs = context.obtainStyledAttributes(attrs, R.styleable.FontFitTextView, defStyle, 0);
            maxTextSize = tAttrs.getDimensionPixelSize(R.styleable.FontFitTextView_maxTextSize, maxTextSize);
            minTextSize = tAttrs.getDimensionPixelSize(R.styleable.FontFitTextView_minTextSize, minTextSize);
            tAttrs.recycle();
    }

    private void resizeText() {
            if (getWidth() <= 0 || getHeight() <= 0)
                    return;
            if(mode == Mode.None)
                    return;

            final int targetWidth = getWidth();
            final int targetHeight = getHeight();

            inComputation = true;
            float higherSize = maxTextSize;
            float lowerSize = minTextSize;
            float textSize = getTextSize();
            while(higherSize - lowerSize > THRESHOLD) {
                    textSize = (higherSize + lowerSize) / 2;
                    if (isTooBig(textSize, targetWidth, targetHeight)) {
                            higherSize = textSize; 
                    } else {
                            lowerSize = textSize;
                    }
            }
            setTextSize(TypedValue.COMPLEX_UNIT_PX, lowerSize);
            measure(widthMeasureSpec, heightMeasureSpec);
            inComputation = false;
    }

    private boolean isTooBig(float textSize, int targetWidth, int targetHeight) {
            setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
            measure(0, 0);
            if(mode == Mode.Both)
                    return getMeasuredWidth() >= targetWidth || getMeasuredHeight() >= targetHeight;
            if(mode == Mode.Width)
                    return getMeasuredWidth() >= targetWidth;
            else
                    return getMeasuredHeight() >= targetHeight;
    }

    private Mode getMode(int widthMeasureSpec, int heightMeasureSpec) {
            int widthMode = MeasureSpec.getMode(widthMeasureSpec);
            int heightMode = MeasureSpec.getMode(heightMeasureSpec);
            if(widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY)
                    return Mode.Both;
            if(widthMode == MeasureSpec.EXACTLY)
                    return Mode.Width;
            if(heightMode == MeasureSpec.EXACTLY)
                    return Mode.Height;
            return Mode.None;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            if(!inComputation) {
                    this.widthMeasureSpec = widthMeasureSpec;
                    this.heightMeasureSpec = heightMeasureSpec;
                    mode = getMode(widthMeasureSpec, heightMeasureSpec);
                    resizeText();
            }
    }

    protected void onTextChanged(final CharSequence text, final int start, final int before, final int after) {
            resizeText();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            if (w != oldw || h != oldh)
                    resizeText();
    }

    public int getMinTextSize() {
            return minTextSize;
    }

    public void setMinTextSize(int minTextSize) {
            this.minTextSize = minTextSize;
            resizeText();
    }

    public int getMaxTextSize() {
            return maxTextSize;
    }

    public void setMaxTextSize(int maxTextSize) {
            this.maxTextSize = maxTextSize;
            resizeText();
    }
}

XML属性文件:

<resources>
    <declare-styleable name="FontFitTextView">
        <attr name="minTextSize" format="dimension" />
        <attr name="maxTextSize" format="dimension" />
    </declare-styleable>
</resources>

请查看我的Github,获取此类的最新版本。 希望它对某些人有用。 如果发现错误或者需要代码解释,请在Github上随意提交一个问题。


它在我的Galaxy Nexus上完美运行,但在屏幕较小的设备上出现了问题。 - Toni Alvarez
你在小屏幕设备上遇到了什么问题? - yDelouis
抱歉,问题不在于小屏幕,您的视图在所有搭载Android 4.0的设备上都无法正常工作,包括模拟器。我已在您的GitHub上开了一个新的问题。 - Toni Alvarez

14

非常感谢https://stackoverflow.com/users/234270/speedplane,给出了很好的回答!

这里是他回答的改进版,还考虑了高度并添加了maxFontSize属性来限制字体大小(在我的情况下非常有用,所以我想分享一下):

package com.<your_package>;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.TextView;


public class FontFitTextView extends TextView
{

    private Paint mTestPaint;
    private float maxFontSize;
    private static final float MAX_FONT_SIZE_DEFAULT_VALUE = 20f;

    public FontFitTextView(Context context)
    {
        super(context);
        initialise(context, null);
    }

    public FontFitTextView(Context context, AttributeSet attributeSet)
    {
        super(context, attributeSet);
        initialise(context, attributeSet);
    }

    public FontFitTextView(Context context, AttributeSet attributeSet, int defStyle)
    {
        super(context, attributeSet, defStyle);
        initialise(context, attributeSet);
    }

    private void initialise(Context context, AttributeSet attributeSet)
    {
        if(attributeSet!=null)
        {
            TypedArray styledAttributes = context.obtainStyledAttributes(attributeSet, R.styleable.FontFitTextView);
            maxFontSize = styledAttributes.getDimension(R.styleable.FontFitTextView_maxFontSize, MAX_FONT_SIZE_DEFAULT_VALUE);
            styledAttributes.recycle();
        }
        else
        {
            maxFontSize = MAX_FONT_SIZE_DEFAULT_VALUE;
        }

        mTestPaint = new Paint();
        mTestPaint.set(this.getPaint());
        //max size defaults to the initially specified text size unless it is too small
    }

    /* 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)
            return;
        int targetWidth = textWidth - this.getPaddingLeft() - this.getPaddingRight();
        int targetHeight = textHeight - this.getPaddingTop() - this.getPaddingBottom();
        float hi = maxFontSize;
        float lo = 2;
//      final float threshold = 0.5f; // How close we have to be
        final float threshold = 1f; // How close we have to be

        mTestPaint.set(this.getPaint());

        Rect bounds = new Rect();

        while ((hi - lo) > threshold)
        {
            float size = (hi + lo) / 2;
            mTestPaint.setTextSize(size);

            mTestPaint.getTextBounds(text, 0, text.length(), bounds);

            if (bounds.width() >= targetWidth || bounds.height() >= targetHeight)
                hi = size; // too big
            else
                lo = size; // too small

//          if (mTestPaint.measureText(text) >= targetWidth)
//              hi = size; // too big
//          else
//              lo = size; // too small
        }
        // Use lo so that we undershoot rather than overshoot
        this.setTextSize(TypedValue.COMPLEX_UNIT_PX, lo);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
        int height = getMeasuredHeight();
        refitText(this.getText().toString(), parentWidth, height);
        this.setMeasuredDimension(parentWidth, height);
    }

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

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh)
    {
        if (w != oldw)
        {
            refitText(this.getText().toString(), w, h);
        }
    }
}

对应的/res/values/attr.xml文件:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="FontFitTextView">
        <attr name="maxFontSize" format="dimension" />
    </declare-styleable>

</resources>

例子:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:res-auto="http://schemas.android.com/apk/res-auto"
    android:id="@+id/home_Layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/background"
    tools:ignore="ContentDescription" >
...

 <com.<your_package>.FontFitTextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:singleLine="true"
                    android:text="Sample Text"
                    android:textSize="28sp"
                    res-auto:maxFontSize="35sp"/>

...
</RelativeLayout>

要使用新的maxFontSize属性,请像示例中显示的那样添加xmlns:res-auto="http://schemas.android.com/apk/res-auto"


抱歉,但它仍然不能在所有情况下正常工作。我也认为它不能正确处理多行。 - android developer
哦...你能给我一个它不起作用的案例吗?(多行不支持,你是对的) - Pascal
很多情况下,我创建了一个随机测试程序来证明它的正确性。这是一个示例: 视图的宽度:317px,高度:137px,文本:"q7Lr"。我看到的是这个:http://tinypic.com/view.php?pic=2dv5yf9&s=6。这是我制作的样例项目: https://mega.co.nz/#!w9QRyBaB!J3KdnyTuNXRsYH9Hk5f4nBBXkRM1IAQnV8-53ckRooY。我认为这样的视图应该处理多行,支持任何字体大小,处理高度而不仅仅是宽度等...遗憾的是,我发现的所有示例都没有良好的效果。 - android developer
好的,这绝对不是一个完整的解决方案。很抱歉,暂时没有时间改进它。如果您能改进它,请毫不犹豫地发布您的解决方案。 - Pascal
1
我创建了一个新的线程展示我的测试,希望有人能够提供一个好的解决方案:https://dev59.com/7WQo5IYBdhLWcg3wfPUa - android developer
我正在尝试在我的小部件上实现这个,但是我一直得不到小部件?我已经在这里发布了一个帮助链接。我知道问题在于view.setTextViewText() - Dino

13
你现在可以在API 26及以上的版本中,不使用第三方库或小部件来实现自适应文本大小。只需将android:autoSizeTextType="uniform" 添加到你的TextView并设置其高度即可。就这么简单。
参考链接:https://developer.android.com/guide/topics/ui/look-and-feel/autosizing-textview.html
<?xml version="1.0" encoding="utf-8"?>
<TextView
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:autoSizeTextType="uniform" />

您还可以使用 TextViewCompatapp:autoSizeTextType="uniform" 来实现向后兼容性。


2
使用app:autoSizeTextType="uniform"以实现向后兼容,因为android:autoSizeTextType="uniform"仅适用于API Level 26及更高版本。 - Atul Bhardwaj

7

我曾经有同样的问题,写了一个类,似乎对我有效。基本上,我使用静态布局在单独的画布上绘制文本,并重新测量,直到找到适合的字体大小。您可以在下面的话题中查看发布的类。希望能帮助到你。

自动缩放TextView文字以适应边界


6

为了向后兼容,请使用app:autoSizeTextType="uniform",因为android:autoSizeTextType="uniform"仅适用于API Level 26及以上。


谢谢Suraj。这是最好的解决方案。 - Atul Bhardwaj
我在SDK 24上检查了一下,它不起作用。你确定 app:.. 在低于26的SDK上能正常工作吗? - Georgiy Chebotarev
是的,它作为应用程序命名空间提供向后兼容性。有一篇详细的文章介绍了它,请查看,也许可以解决您的问题。https://medium.com/over-engineering/making-the-most-of-textview-auto-sizing-on-android-a39f71b6f3af - Suraj Vaishnav

5

对onMeasure进行轻微修改:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
    int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
    refitText(this.getText().toString(), parentWidth);
    this.setMeasuredDimension(parentWidth, parentHeight);
}

在refitText上进行二分查找:

private void refitText(String text, int textWidth) 
{ 
    if (textWidth > 0) 
    {
        int availableWidth = textWidth - this.getPaddingLeft() - this.getPaddingRight();         
        int trySize = (int)maxTextSize;
        int increment = ~( trySize - (int)minTextSize ) / 2;

        testPaint.setTextSize(trySize);
        while ((trySize > minTextSize) && (testPaint.measureText(text) > availableWidth)) 
        {
            trySize += increment;
            increment = ( increment == 0 ) ? -1 : ~increment / 2;
            if (trySize <= minTextSize) 
            {
                trySize = (int)minTextSize;
                break;
            }
            testPaint.setTextSize(trySize);
        }

        this.setTextSize( TypedValue.COMPLEX_UNIT_PX, trySize);
    }
}

3
不使用二分搜索,简单的缩放也可以很有效:trySize *= availableWidth / measured_width(然后被限制在minTextSize)。 - Ted Hopp

5
我发现以下内容对我有很好的作用。它不会循环并且考虑了高度和宽度。请注意,调用视图上的setTextSize时指定PX单位非常重要。感谢前一篇帖子中的提示!
Paint paint = adjustTextSize(getPaint(), numChars, maxWidth, maxHeight);
setTextSize(TypedValue.COMPLEX_UNIT_PX,paint.getTextSize());

这是我使用的例程,通过从视图中传递getPaint()。使用一个带有“宽”字符的10个字符字符串来估算与实际字符串无关的宽度。

private static final String text10="OOOOOOOOOO";
public static Paint adjustTextSize(Paint paint, int numCharacters, int widthPixels, int heightPixels) {
    float width = paint.measureText(text10)*numCharacters/text10.length();
    float newSize = (int)((widthPixels/width)*paint.getTextSize());
    paint.setTextSize(newSize);

    // remeasure with font size near our desired result
    width = paint.measureText(text10)*numCharacters/text10.length();
    newSize = (int)((widthPixels/width)*paint.getTextSize());
    paint.setTextSize(newSize);

    // Check height constraints
    FontMetricsInt metrics = paint.getFontMetricsInt();
    float textHeight = metrics.descent-metrics.ascent;
    if (textHeight > heightPixels) {
        newSize = (int)(newSize * (heightPixels/textHeight));
        paint.setTextSize(newSize);
    }

    return paint;
}

你如何在布局XML中将其整合进去? - AlikElzin-kilaka
这段代码可用于将文本放置在现有视图中的受限大小区域内,或者您可以从TextView创建自己的派生类,并覆盖其他帖子中所示的onMeasure方法。它本身不能用于布局。 - Glenn
请确保在视图绘制完成后再检查其尺寸。在onCreate()期间执行此操作太早了。我使用ViewTreeObserver来确保在正确的时间进行测量。 - SMBiggs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接