Skip to content

Instantly share code, notes, and snippets.

@vinc3m1
Last active September 28, 2017 07:23
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vinc3m1/11195444 to your computer and use it in GitHub Desktop.
Save vinc3m1/11195444 to your computer and use it in GitHub Desktop.
AutoFitTextUtil
package com.example;
import android.text.Editable;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.text.TextWatcher;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;
import android.widget.TextView;
/**
* @author Vince Mi
*
* Based on Grantland Chew's AutoFitTextView (https://github.com/grantland/android-autofittextview)
* This allows us provide functionality to any TextView subclass without having to create another custom view
*/
public class AutoFitTextUtil implements TextWatcher, View.OnLayoutChangeListener {
private final TextView view;
private final DisplayMetrics displayMetrics;
private final TextPaint mPaint = new TextPaint();
private final float maxTextSize;
private final float minTextSize = 0; // todo set in constructor or something
private final int maxLines = 1; // todo
private final float precision = 0.5f; // todo set in constructor
/**
* Use this method to attach to a view so we can update its text to fit
*/
public static void attachListeners(TextView view) {
AutoFitTextUtil autoFitUtil = new AutoFitTextUtil(view);
view.addTextChangedListener(autoFitUtil);
view.addOnLayoutChangeListener(autoFitUtil);
}
private AutoFitTextUtil(TextView view) {
this.view = view;
this.displayMetrics = view.getResources().getDisplayMetrics();
this.maxTextSize = view.getTextSize();
}
public void refitText() {
String text = view.getText().toString();
int targetWidth = view.getWidth() - view.getPaddingLeft() - view.getPaddingRight();
if (targetWidth > 0) {
float size = maxTextSize;
float high = size;
float low = 0;
mPaint.set(view.getPaint());
mPaint.setTextSize(size);
if ((maxLines == 1 && mPaint.measureText(text) > targetWidth)
|| getLineCount(text, mPaint, size, targetWidth, displayMetrics) > maxLines) {
size = getTextSize(text, mPaint, targetWidth, maxLines, low, high, precision,
displayMetrics);
}
if (size < minTextSize) {
size = minTextSize;
}
view.setTextSize(TypedValue.COMPLEX_UNIT_PX, size);
}
}
/**
* Recursive binary search to find the best size for the text
*/
private static float getTextSize(String text, TextPaint paint,
float targetWidth, int maxLines,
float low, float high, float precision,
DisplayMetrics displayMetrics) {
float mid = (low + high) / 2.0f;
int lineCount = 1;
StaticLayout layout = null;
paint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, mid,
displayMetrics));
if (maxLines != 1) {
layout = new StaticLayout(text, paint, (int) targetWidth, Layout.Alignment.ALIGN_NORMAL,
1.0f, 0.0f, true);
lineCount = layout.getLineCount();
}
//Timber.d("low=" + low + " high=" + high + " mid=" + mid
// + " target=" + targetWidth + " maxLines=" + maxLines + " lineCount=" + lineCount);
if (lineCount > maxLines) {
return getTextSize(text, paint, targetWidth, maxLines, low, mid, precision,
displayMetrics);
} else if (lineCount < maxLines) {
return getTextSize(text, paint, targetWidth, maxLines, mid, high, precision,
displayMetrics);
} else {
float maxLineWidth = 0;
if (maxLines == 1) {
maxLineWidth = paint.measureText(text);
} else {
for (int i = 0; i < lineCount; i++) {
if (layout.getLineWidth(i) > maxLineWidth) {
maxLineWidth = layout.getLineWidth(i);
}
}
}
if ((high - low) < precision) {
return low;
} else if (maxLineWidth > targetWidth) {
return getTextSize(text, paint, targetWidth, maxLines, low, mid, precision,
displayMetrics);
} else if (maxLineWidth < targetWidth) {
return getTextSize(text, paint, targetWidth, maxLines, mid, high, precision,
displayMetrics);
} else {
return mid;
}
}
}
private static int getLineCount(String text, TextPaint paint, float size, float width,
DisplayMetrics displayMetrics) {
paint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, size,
displayMetrics));
StaticLayout layout = new StaticLayout(text, paint, (int) width,
Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, true);
return layout.getLineCount();
}
@Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override public void onTextChanged(CharSequence s, int start, int before, int count) {
refitText();
}
@Override public void afterTextChanged(Editable s) {
}
@Override public void onLayoutChange(View v, int left, int top, int right, int bottom,
int oldLeft, int oldTop, int oldRight, int oldBottom) {
refitText();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment