Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to auto-adjust text size on a multi-line TextView according to the view max dimensions?

Tags:

I've been searching for a way of auto fit a text inside a textview. Through my search I've found many solutions like:

  • FontFitTextView
  • AutoResizeTextView
  • AutoScale/Resize

But like many others these doesn't solve my problem. They don't work as expected when we use a TextView with multiline.

Basically my goal is this one:

Phase 1Phase 2Phase 3Phase 4

As you can see, the text resizes based on width, height and also pays attention to the line break, creating a multi-line textview. Also be able to change the typeface.

One of my ideas to solve this was something like this:

int size = CONSTANT_MAX_SIZE; TextView tv = (TextView) findViewById(R.id.textview1) while(Math.abs(tv.getMeasuredHeight()) >= TEXTVIEW_MAX_HEIGHT) {     size--;     tv.setTextSize(size);     tv.measure(MeasureSpec.UNSPECIFIED,MeasureSpec.UNSPECIFIED);     i++; } 

CONSTANT_MAX_SIZE is a constant that defines the max size of the font (textsize propriety in a TextView)

TEXTVIEW_MAX_HEIGHT is a constant that defines the max size that the textview can have.

This was called every time the text in the textview was changed.

The textview xml was something like this:

<TextView      android:id="@+id/textview1"      android:layout_width="200dp"      android:layout_height="wrap_content"      android:singleLine="false"      android:inputType="textMultiLine"      android:text=""      android:textSize="150sp" /> 

Since the width would be limited in the XML, only the height of the view needs to be considered since adjusting it android would automatically create a multiline when needed.

Although this is a potential solution isn't working perfectly (far from it) and it doesn't support resize down (when you delete text).

Any sugestions and/or ideas?

like image 235
nunofmendes Avatar asked Apr 18 '13 12:04

nunofmendes


People also ask

How do I Auto Resize TextView?

To use preset sizes to set up the autosizing of TextView in XML, use the android namespace and set the following attributes: Set the autoSizeText attribute to either none or uniform. none is a default value and uniform lets TextView scale uniformly on horizontal and vertical axes.

Which method is used to change the text size of the TextView?

To use preset sizes to set up the autosizing of TextView programmatically, call the setAutoSizeTextTypeUniformWithPresetSizes(int[] presetSizes, int unit) method. Provide an array of sizes and any TypedValue dimension unit for the size.

Which attribute increase or decrease the font size of TextView?

app:autoSizeMinTextSize=”10sp” using this attribute the TextView will be resized up to the size of 10sp and app:autoSizeStepGranularity=”2sp” using this attribute we are uniformly reducing the size of the TextView as 2sp when it goes out of the screen.


1 Answers

While I waited for a possible solution to this question, I have been experimenting and trying to figure it out.

The closest solution to this problem was based in a method from paint.

Basically paint has a method called 'breaktext' which:

public int breakText (CharSequence text, int start, int end, boolean measureForwards, float maxWidth, float[] measuredWidth)

Added in API level 1

Measure the text, stopping early if the measured width exceeds maxWidth. Return the number of chars that were measured, and if measuredWidth is not null, return in it the actual width measured.

I combine that with paint 'getTextBounds' which:

public void getTextBounds (String text, int start, int end, Rect bounds)

Added in API level 1

Return in bounds (allocated by the caller) the smallest rectangle that encloses all of the >characters, with an implied origin at (0,0).

So now I can obtain the number of chars that fit in a given width and the height of those chars.

Using a while you can keep moving the removing chars from the string you want to measure and obtain the number of lines (by using a while(index < string.length)) and multiply that by the height obtained in the getTextBounds.

Additionally you will have to add a variable height for each two lines that represent the space between the lines (which is not counted in the getTextBounds).

As an example code, the function to know the height of a multiple line text is something like this:

public int getHeightOfMultiLineText(String text,int textSize, int maxWidth) {     paint = new TextPaint();     paint.setTextSize(textSize);     int index = 0;     int linecount = 0;     while(index < text.length()) {         index += paint.breakText(text,index,text.length,true,maxWidth,null);         linecount++;     }      Rect bounds = new Rect();     paint.getTextBounds("Yy", 0, 2, bounds);     // obtain space between lines     double lineSpacing = Math.max(0,((lineCount - 1) * bounds.height()*0.25));       return (int)Math.floor(lineSpacing + lineCount * bounds.height()); 

Note: maxWidth variable is in pixels

Then you will have to call this method inside a while to determine what is the max font size for that height. An example code would be:

textSize = 100; int maxHeight = 50; while(getHeightOfMultiLineText(text,textSize,maxWidth) > maxHeight)   textSize--; 

Unfortunately this was the only (as far as I know) way I was able to achieve the aspect from the images above.

Hope this can be of help to anyone trying to overcome this obstacle.

like image 86
nunofmendes Avatar answered Oct 06 '22 22:10

nunofmendes