blob: c37d085fb3ab1fa193d7d9cd7affcc93ca6f3618 [file] [log] [blame]
package com.android.tv.settings.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.text.Layout;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.TextView;
import java.text.BreakIterator;
import com.android.tv.settings.R;
/**
* <p>A {@link android.widget.TextView} that changes the font size depending on the text width.</p>
*
* <p>We check for two signals that indicates that the text view is too small for the given text:
* 1. whether there is an ellipsis, and 2. whether a word spans two lines. If either of these
* conditions are met, we move down to a smaller font size. If the text is still too big after
* resizing, we give up.</p>
*
* <p>This method is not completely fool-proof because the string tokenizing method used by
* StaticLayout is not the same as we use here. So some things (e.g. email addresses) might be
* wrapped without shrinking.</p>
*/
public class ResizingTextView extends TextView {
public ResizingTextView(Context ctx, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(ctx, attrs, defStyleAttr, defStyleRes);
}
public ResizingTextView(Context ctx, AttributeSet attrs, int defStyleAttr) {
super(ctx, attrs, defStyleAttr);
}
public ResizingTextView(Context ctx, AttributeSet attrs) {
super(ctx, attrs);
}
public ResizingTextView(Context ctx) {
super(ctx);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
boolean switchToSmallFont = false;
final Layout layout = getLayout();
if (layout != null) {
final int lineCount = layout.getLineCount();
if (lineCount > 0) {
final int ellipsisCount = layout.getEllipsisCount(lineCount - 1);
if (ellipsisCount > 0) {
// Always just go to small font if we have to ellipsize.
switchToSmallFont = true;
} else {
// No ellipsis, but we could have words that span lines.
BreakIterator iter = BreakIterator.getWordInstance();
iter.setText(getText().toString());
int breakIndex = iter.next();
for (int line = 0; line < layout.getLineCount() - 1; line++) {
iter.following(layout.getLineStart(line));
if (breakIndex > layout.getLineVisibleEnd(line)) {
// Line breaks before a word boundary.
switchToSmallFont = true;
break;
}
}
}
}
}
if (switchToSmallFont) {
final int normalSizePx = mContext.getResources().getDimensionPixelSize(
R.dimen.browse_item_title_font_size);
final int smallSizePx = mContext.getResources().getDimensionPixelSize(
R.dimen.browse_item_title_font_size_small);
// In addition to setting the text size, we fudge the line spacing and padding so it
// doesn't look so strange next to non-resized text.
setTextSize(TypedValue.COMPLEX_UNIT_PX, smallSizePx);
setLineSpacing(normalSizePx - smallSizePx, 1.0f);
setPaddingRelative(0, 0, 0, (normalSizePx - smallSizePx) / 2);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
}