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; /** *
A {@link android.widget.TextView} that changes the font size depending on the text width.
* *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.
* *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.
*/ 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); } } }