• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.android.tv.settings.widget;
2 
3 import android.content.Context;
4 import android.content.res.TypedArray;
5 import android.text.Layout;
6 import android.util.AttributeSet;
7 import android.util.TypedValue;
8 import android.widget.TextView;
9 
10 import java.text.BreakIterator;
11 
12 import com.android.tv.settings.R;
13 
14 /**
15  * <p>A {@link android.widget.TextView} that changes the font size depending on the text width.</p>
16  *
17  * <p>We check for two signals that indicates that the text view is too small for the given text:
18  * 1. whether there is an ellipsis, and 2. whether a word spans two lines.  If either of these
19  * conditions are met, we move down to a smaller font size.  If the text is still too big after
20  * resizing, we give up.</p>
21  *
22  * <p>This method is not completely fool-proof because the string tokenizing method used by
23  * StaticLayout is not the same as we use here.  So some things (e.g. email addresses) might be
24  * wrapped without shrinking.</p>
25  */
26 public class ResizingTextView extends TextView {
27 
ResizingTextView(Context ctx, AttributeSet attrs, int defStyleAttr, int defStyleRes)28     public ResizingTextView(Context ctx, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
29         super(ctx, attrs, defStyleAttr, defStyleRes);
30     }
31 
ResizingTextView(Context ctx, AttributeSet attrs, int defStyleAttr)32     public ResizingTextView(Context ctx, AttributeSet attrs, int defStyleAttr) {
33         super(ctx, attrs, defStyleAttr);
34     }
35 
ResizingTextView(Context ctx, AttributeSet attrs)36     public ResizingTextView(Context ctx, AttributeSet attrs) {
37         super(ctx, attrs);
38     }
39 
ResizingTextView(Context ctx)40     public ResizingTextView(Context ctx) {
41         super(ctx);
42     }
43 
44     @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)45     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
46         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
47         boolean switchToSmallFont = false;
48 
49         final Layout layout = getLayout();
50         if (layout != null) {
51             final int lineCount = layout.getLineCount();
52             if (lineCount > 0) {
53                 final int ellipsisCount = layout.getEllipsisCount(lineCount - 1);
54                 if (ellipsisCount > 0) {
55                     // Always just go to small font if we have to ellipsize.
56                     switchToSmallFont = true;
57                 } else {
58                     // No ellipsis, but we could have words that span lines.
59                     BreakIterator iter = BreakIterator.getWordInstance();
60                     iter.setText(getText().toString());
61                     int breakIndex = iter.next();
62                     for (int line = 0; line < layout.getLineCount() - 1; line++) {
63                         iter.following(layout.getLineStart(line));
64                         if (breakIndex > layout.getLineVisibleEnd(line)) {
65                             // Line breaks before a word boundary.
66                             switchToSmallFont = true;
67                             break;
68                         }
69                     }
70                 }
71             }
72         }
73 
74         if (switchToSmallFont) {
75             final int normalSizePx = mContext.getResources().getDimensionPixelSize(
76                     R.dimen.browse_item_title_font_size);
77             final int smallSizePx = mContext.getResources().getDimensionPixelSize(
78                     R.dimen.browse_item_title_font_size_small);
79 
80             // In addition to setting the text size, we fudge the line spacing and padding so it
81             // doesn't look so strange next to non-resized text.
82             setTextSize(TypedValue.COMPLEX_UNIT_PX, smallSizePx);
83             setLineSpacing(normalSizePx - smallSizePx, 1.0f);
84             setPaddingRelative(0, 0, 0, (normalSizePx - smallSizePx) / 2);
85             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
86         }
87     }
88 }
89