1
+
2
+ import android .content .Context ;
3
+ import android .text .Layout .Alignment ;
4
+ import android .text .StaticLayout ;
5
+ import android .text .TextPaint ;
6
+ import android .util .AttributeSet ;
7
+ import android .util .TypedValue ;
8
+ import android .widget .TextView ;
9
+
10
+ /**
11
+ *
12
+ * SizeAdjustingTextView is a TextView that adjusts text size
13
+ * depending if or if not it will fit in the view bounds.
14
+ * Copyright (C) 2014 Elliott Chenger
15
+ *
16
+ * This program is free software; you can redistribute it and/or
17
+ * modify it under the terms of the GNU General Public License
18
+ * as published by the Free Software Foundation; either version 2
19
+ * of the License, or (at your option) any later version.
20
+ *
21
+ * This program is distributed in the hope that it will be useful,
22
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24
+ * GNU General Public License for more details.
25
+ *
26
+ * You should have received a copy of the GNU General Public License
27
+ * along with this program; if not, write to the Free Software
28
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
29
+ *
30
+ * @author Elliott Chenger
31
+ * @since Jan 18, 2014
32
+ * @author Chase Colburn
33
+ * @since Apr 4, 2011
34
+ *
35
+ */
36
+ public class SizeAdjustingTextView extends TextView {
37
+
38
+ // Minimum text size for this text view
39
+ public static final float MIN_TEXT_SIZE = 20 ;
40
+
41
+ // Our ellipse string
42
+ private static final String mEllipsis = "..." ;
43
+
44
+ // Flag for text and/or size changes to force a resize
45
+ private boolean mNeedsResize = false ;
46
+
47
+ // Text size that is set from code. This acts as a starting point for resizing
48
+ private float mTextSize ;
49
+
50
+ // Temporary upper bounds on the starting text size
51
+ private float mMaxTextSize = 0 ;
52
+
53
+ // Lower bounds for text size
54
+ private float mMinTextSize = MIN_TEXT_SIZE ;
55
+
56
+ // Text view line spacing multiplier
57
+ private float mSpacingMult = 1.0f ;
58
+
59
+ // Text view additional line spacing
60
+ private float mSpacingAdd = 0.0f ;
61
+
62
+ // Add ellipsis to text that overflows at the smallest text size
63
+ private boolean mAddEllipsis = true ;
64
+
65
+ // Default constructor override
66
+ public SizeAdjustingTextView (Context context ) {
67
+ this (context , null );
68
+ }
69
+
70
+ // Default constructor when inflating from XML file
71
+ public SizeAdjustingTextView (Context context , AttributeSet attrs ) {
72
+ this (context , attrs , 0 );
73
+ }
74
+
75
+ // Default constructor override
76
+ public SizeAdjustingTextView (Context context , AttributeSet attrs , int defStyle ) {
77
+ super (context , attrs , defStyle );
78
+ mTextSize = getTextSize ();
79
+ }
80
+
81
+ @ Override
82
+ protected void onTextChanged (final CharSequence text , final int start , final int before , final int after ) {
83
+ mNeedsResize = true ;
84
+ // Since this view may be reused, it is good to reset the text size
85
+ resetTextSize ();
86
+ }
87
+
88
+ @ Override
89
+ public void setText (CharSequence text , BufferType type ) {
90
+ super .setText (text , type );
91
+ resizeText ();
92
+ }
93
+
94
+ @ Override
95
+ protected void onSizeChanged (int w , int h , int oldw , int oldh ) {
96
+ if (w != oldw || h != oldh ) {
97
+ mNeedsResize = true ;
98
+ }
99
+ }
100
+
101
+
102
+ @ Override
103
+ public void setTextSize (float size ) {
104
+ super .setTextSize (size );
105
+ mTextSize = getTextSize ();
106
+ }
107
+
108
+ @ Override
109
+ public void setTextSize (int unit , float size ) {
110
+ super .setTextSize (unit , size );
111
+ mTextSize = getTextSize ();
112
+ }
113
+
114
+ @ Override
115
+ public void setLineSpacing (float add , float mult ) {
116
+ super .setLineSpacing (add , mult );
117
+ mSpacingMult = mult ;
118
+ mSpacingAdd = add ;
119
+ }
120
+
121
+ public void setMaxTextSize (float maxTextSize ) {
122
+ mMaxTextSize = maxTextSize ;
123
+ requestLayout ();
124
+ invalidate ();
125
+ }
126
+
127
+ public float getMaxTextSize () {
128
+ return mMaxTextSize ;
129
+ }
130
+
131
+ public void setMinTextSize (float minTextSize ) {
132
+ mMinTextSize = minTextSize ;
133
+ requestLayout ();
134
+ invalidate ();
135
+ }
136
+
137
+ public float getMinTextSize () {
138
+ return mMinTextSize ;
139
+ }
140
+
141
+ public void setAddEllipsis (boolean addEllipsis ) {
142
+ mAddEllipsis = addEllipsis ;
143
+ }
144
+
145
+ public boolean getAddEllipsis () {
146
+ return mAddEllipsis ;
147
+ }
148
+
149
+ public void resetTextSize () {
150
+ if (mTextSize > 0 ) {
151
+ super .setTextSize (TypedValue .COMPLEX_UNIT_PX , mTextSize );
152
+ mMaxTextSize = mTextSize ;
153
+ }
154
+ }
155
+
156
+ @ Override
157
+ protected void onLayout (boolean changed , int left , int top , int right , int bottom ) {
158
+ if (changed || mNeedsResize ) {
159
+ int widthLimit = (right - left ) - getCompoundPaddingLeft () - getCompoundPaddingRight ();
160
+ int heightLimit = (bottom - top ) - getCompoundPaddingBottom () - getCompoundPaddingTop ();
161
+ resizeText (widthLimit , heightLimit );
162
+ }
163
+ super .onLayout (changed , left , top , right , bottom );
164
+ }
165
+
166
+
167
+ public void resizeText () {
168
+ int heightLimit = getHeight () - getPaddingBottom () - getPaddingTop ();
169
+ int widthLimit = getWidth () - getPaddingLeft () - getPaddingRight ();
170
+ resizeText (widthLimit , heightLimit );
171
+ }
172
+
173
+ public void resizeText (int width , int height ) {
174
+ CharSequence text = getText ();
175
+ if (text == null || text .length () == 0 || height <= 0 || width <= 0 || mTextSize == 0 ) {
176
+ return ;
177
+ }
178
+ float newTextSize = findNewTextSize (width , height , text );
179
+ changeTextSize (newTextSize );
180
+ mNeedsResize = false ;
181
+ }
182
+
183
+ private void changeTextSize (float newTextSize ) {
184
+ setTextSize (TypedValue .COMPLEX_UNIT_PX ,newTextSize );
185
+ setLineSpacing (mSpacingAdd , mSpacingMult );
186
+ }
187
+
188
+ private float findNewTextSize (int width , int height , CharSequence text ) {
189
+ TextPaint textPaint = new TextPaint (getPaint ());
190
+
191
+ float targetTextSize = textPaint .getTextSize ();
192
+
193
+ int textHeight = getTextHeight (text , textPaint , width , targetTextSize );
194
+ while (textHeight > height && targetTextSize > mMinTextSize ) {
195
+ targetTextSize = Math .max (targetTextSize - 1 , mMinTextSize );
196
+ textHeight = getTextHeight (text , textPaint , width , targetTextSize );
197
+ }
198
+ return targetTextSize ;
199
+ }
200
+
201
+ private int getTextHeight (CharSequence source , TextPaint paint , int width , float textSize ) {
202
+ paint .setTextSize (textSize );
203
+ StaticLayout layout = new StaticLayout (source , paint , width , Alignment .ALIGN_NORMAL , mSpacingMult , mSpacingAdd , true );
204
+ return layout .getHeight ();
205
+ }
206
+
207
+ }
0 commit comments