Last active
September 28, 2017 07:23
-
-
Save vinc3m1/11195444 to your computer and use it in GitHub Desktop.
AutoFitTextUtil
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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