package com.samknows.measurement.activity.components;
import android.content.Context;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.TextView;
// Based on https://stackoverflow.com/questions/2617266/how-to-adjust-text-font-size-to-fit-textview
// A version of TextView that automatically scales-back the font size to fit the available space.
// This does not always work as expected on real devices (usually fine on the Emulator), hence
// we also have both LargeTextFontFitTextView and FontFitTextView as alternatives.
public class CustomFontFitTextView extends TextView {
private float initialTextSizePx = 200;
public CustomFontFitTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initialTextSizePx = getTextSize();
initialise();
}
public CustomFontFitTextView(Context context, AttributeSet attrs) {
super(context, attrs);
initialTextSizePx = getTextSize();
initialise();
}
public CustomFontFitTextView(Context context) {
super(context);
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
}
// https://stackoverflow.com/questions/6263250/convert-pixels-to-sp
public static float spToPixels(Context context, Float sp) {
float scaledDensity = context.getResources().getDisplayMetrics().scaledDensity;
return scaledDensity * sp;
}
/* 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 (text.length() == 0) {
return;
}
if (textWidth <= 0)
return;
if (textHeight <= 0)
return;
int targetWidth = textWidth - this.getPaddingLeft() - this.getPaddingRight();
int targetHeight = textHeight - this.getPaddingTop() - this.getPaddingBottom();
//final float hiSp = 16;
//float hi = spToPixels(getContext(), hiSp);
float hi = initialTextSizePx;
float lo = 2;
final float threshold = 0.5f; // How close we have to be
mTestPaint.set(this.getPaint());
// Home-in on the correct size to use - hi is upper bounds, lo is lower bounds.
// NB the text bounds calculation doesn't account for multi-line text.
// So if we need to account for this: if we have > 1 line, we need to sum-up the total line heights,
// and use the maximum width.
String[] lines = text.split("\n");
// Notes:
// - we finish when lo and hi are within a small difference threshold (0.5F)
// - we use lo so that we are likely to be slightly too narrow rather than slightly too wide!
while((hi - lo) > threshold) {
float size = (hi+lo)/2;
mTestPaint.setTextSize(size);
Rect bounds = new Rect();
float maxWidth = 0.0F;
float totalHeight = 0.0F;
int lineCount = lines.length;
for (String theLine : lines) {
// Using getTextBounds accounts for multi-line text; measure text does *not*!
mTestPaint.getTextBounds(theLine, 0, theLine.length(), bounds);
maxWidth = Math.max(bounds.width(), maxWidth);
totalHeight += bounds.height();
}
if (maxWidth >= targetWidth) {
hi = size; // too big
}
else if (totalHeight >= targetHeight) {
hi = size; // too big
}
else {
lo = size; // too small
}
}
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 parentHeight = MeasureSpec.getSize(heightMeasureSpec);
int height = getMeasuredHeight();
refitText(this.getText().toString(), parentWidth, parentHeight);
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);
}
}
//Attributes
private Paint mTestPaint;
// // Enable the following if you want some yellow debug boxes drawn around your items!
// @Override
// protected void onDraw(Canvas canvas) {
// // TODO Auto-generated method stub
// super.onDraw(canvas);
//
// Paint paint = new Paint();
// paint.setColor(Color.CYAN);
// paint.setStyle(Style.STROKE);
// canvas.drawRect(new Rect(0,0,getWidth()-1, getHeight()-1), paint);
// }
}