Calculate text size according to width of text area
Asked Answered
P

7

32

I have a text that should be set to TextView with specified width. It needs to calculate the text size to fit it into TextView.

In other words: Is there a way to fit text into TextView area, like the ImageView scale type feature?

Pelletier answered 25/1, 2011 at 14:15 Comment(1)
Check this answer here https://mcmap.net/q/55773/-scale-text-in-a-view-to-fit/…Gurgle
W
36

This should be a simple solution:

public void correctWidth(TextView textView, int desiredWidth)
{
    Paint paint = new Paint();
    Rect bounds = new Rect();

    paint.setTypeface(textView.getTypeface());
    float textSize = textView.getTextSize();
    paint.setTextSize(textSize);
    String text = textView.getText().toString();
    paint.getTextBounds(text, 0, text.length(), bounds);

    while (bounds.width() > desiredWidth)
    {
        textSize--;
        paint.setTextSize(textSize);
        paint.getTextBounds(text, 0, text.length(), bounds);
    }

    textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
}
Warble answered 23/9, 2013 at 11:52 Comment(3)
what is desired width? I need to match_parentHandbill
BTW you can get a paint directly from textViewCyclohexane
This solution doesn't take in account potential desiredWidth grow (if it grows, textSize won't change)Cyclohexane
A
29

If it is the Size of the space the Text takes your after then the following might help:

Paint paint = new Paint();
Rect bounds = new Rect();

int text_height = 0;
int text_width = 0;

paint.setTypeface(Typeface.DEFAULT);// your preference here
paint.setTextSize(25);// have this the same as your text size

String text = "Some random text";

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

text_height =  bounds.height();
text_width =  bounds.width();

Edit (after comment): Use the above in reverse:

int text_height = 50;
int text_width = 200;

int text_check_w = 0;
int text_check_h = 0;

int incr_text_size = 1;
boolean found_desired_size = true;

while (found_desired_size){
    paint.setTextSize(incr_text_size);// have this the same as your text size

    String text = "Some random text";

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

    text_check_h =  bounds.height();
    text_check_w =  bounds.width();
    incr_text_size++;

if (text_height == text_check_h && text_width == text_check_w){
found_desired_size = false;
}
}
return incr_text_size; // this will be desired text size from bounds you already have

//this method may be tweaked a bit, but gives you an idea on what you can do

Ainslee answered 25/1, 2011 at 15:34 Comment(2)
It is not exactly what I want. I don't need to calculate the text height/width according to text size and font. I need to calculate the text size according to height/width and font.Pelletier
@Pelletier : didi you get answer ?Sahara
N
13
 public static float getFitTextSize(TextPaint paint, float width, String text) {
     float nowWidth = paint.measureText(text);
     float newSize = (float) width / nowWidth * paint.getTextSize();
     return newSize;
 }
Nominalism answered 19/5, 2015 at 14:42 Comment(5)
Please explain your code so that the asker understands your solution.Shellback
This should be the accepted solution. The fastest and the simplest.Fondness
Simple and fastOppress
When and where do you call this? onCreate() is too soon as most Views aren't ready yet. Or am I missing something obvious?Bensen
@ScottBiggs you can call it inside view.post(), it's called when view is ready to drawOrgiastic
P
3

I needed one that calculates best fit for both width and height, in pixels. This is my solution:

private static int getFitTextSize(Paint paint, int width, int height, String text) {
   int maxSizeToFitWidth = (int)((float)width / paint.measureText(text) * paint.getTextSize());
   return Math.min(maxSizeToFitWidth, height);
}
Popularly answered 5/7, 2019 at 8:36 Comment(0)
T
2

I also had to face the same problem when having to ensure that text fits into a specific box. The following is the best performing and most accurate solution that I have for it at the moment:

/**
 * A paint that has utilities dealing with painting text.
 * @author <a href="maillto:nospam">Ben Barkay</a>
 * @version 10, Aug 2014
 */
public class TextPaint extends android.text.TextPaint {
    /**
     * Constructs a new {@code TextPaint}.
     */
    public TextPaint() {
        super();
    }

    /**
     * Constructs a new {@code TextPaint} using the specified flags
     * @param flags
     */
    public TextPaint(int flags) {
        super(flags);
    }

    /**
     * Creates a new {@code TextPaint} copying the specified {@code source} state.
     * @param source The source paint to copy state from.
     */
    public TextPaint(Paint source) {
        super(source);
    }

    // Some more utility methods...

    /**
     * Calibrates this paint's text-size to fit the specified text within the specified width.
     * @param text      The text to calibrate for.
     * @param boxWidth  The width of the space in which the text has to fit.
     */
    public void calibrateTextSize(String text, float boxWidth) {
        calibrateTextSize(text, 0, Float.MAX_VALUE, boxWidth);
    }

    /**
     * Calibrates this paint's text-size to fit the specified text within the specified width.
     * @param text      The text to calibrate for.
     * @param min       The minimum text size to use.
     * @param max       The maximum text size to use.
     * @param boxWidth  The width of the space in which the text has to fit.
     */
    public void calibrateTextSize(String text, float min, float max, float boxWidth) {
        setTextSize(10);
        setTextSize(Math.max(Math.min((boxWidth/measureText(text))*10, max), min));
    }
}

This simply calculates the correct size rather than running a trial/error test.

You can use it like this:

float availableWidth = ...; // use your text view's width, or any other width.
String text = "Hi there";
TextPaint paint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
paint.setTypeface(...);
paint.calibrateTextSize(text, availableWidth);

Or otherwise, without the extra type:

/**
 * Calibrates this paint's text-size to fit the specified text within the specified width.
 * @param paint     The paint to calibrate.
 * @param text      The text to calibrate for.
 * @param min       The minimum text size to use.
 * @param max       The maximum text size to use.
 * @param boxWidth  The width of the space in which the text has to fit.
 */
public static void calibrateTextSize(Paint paint, String text, float min, float max, float boxWidth) {
    paint.setTextSize(10);
    paint.setTextSize(Math.max(Math.min((boxWidth/paint.measureText(text))*10, max), min));
}

Use like so:

float availableWidth = ...; // use your text view's width, or any other width.
String text = "Hi there";
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setTypeface(...);
calibrateTextSize(paint, text, 0, Float.MAX_VALUE, availableWidth);
Terramycin answered 10/8, 2014 at 15:24 Comment(0)
C
0

This solution in Kotlin takes into account both width growth and reduction:

    private fun TextView.updateTextSize(desiredTextViewWidth: Int, text: String) {
        var lastFitSize = 0f
        var foundMaxSize = false

        while (!foundMaxSize && lastFitSize < Float.MAX_VALUE) {
            paint.textSize = lastFitSize + 1

            foundMaxSize = paint.measureText(text) > desiredTextViewWidth
            if (!foundMaxSize) {
                lastFitSize = paint.textSize
            }
        }

        setTextSize(TypedValue.COMPLEX_UNIT_PX, lastFitSize)
    }
Cyclohexane answered 28/7, 2021 at 16:9 Comment(0)
M
0

Now there is a new API for text auto sizing

https://developer.android.com/guide/topics/ui/look-and-feel/autosizing-textview

<TextView
    android:layout_width="match_parent"
    android:layout_height="200dp"
    app:autoSizeTextType="uniform"
    pp:autoSizeMinTextSize="12sp"       
    app:autoSizeMaxTextSize="100sp".     
    app:autoSizeStepGranularity="2sp" /> 

Note: If you use autosizing, it is not recommended to use the value "wrap_content" for the layout_width or layout_height attributes

Malar answered 21/10, 2021 at 18:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.