Skip to content

Commit a2397f6

Browse files
author
AndroidDeveloperLB
committed
First commit of code.
1 parent d0d5277 commit a2397f6

File tree

23 files changed

+655
-0
lines changed

23 files changed

+655
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/AutoFitTextViewLibrary/gen
2+
/AutoFitTextViewLibrary/bin
3+
/AutoFitTextViewSample/bin
4+
/AutoFitTextViewSample/gen

AutoFitTextViewLibrary/.classpath

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<classpath>
3+
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
4+
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
5+
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
6+
<classpathentry kind="src" path="gen"/>
7+
<classpathentry kind="src" path="src"/>
8+
<classpathentry kind="output" path="bin/classes"/>
9+
</classpath>

AutoFitTextViewLibrary/.project

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<projectDescription>
3+
<name>AutoFitTextViewLibrary</name>
4+
<comment></comment>
5+
<projects>
6+
</projects>
7+
<buildSpec>
8+
<buildCommand>
9+
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
10+
<arguments>
11+
</arguments>
12+
</buildCommand>
13+
<buildCommand>
14+
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
15+
<arguments>
16+
</arguments>
17+
</buildCommand>
18+
<buildCommand>
19+
<name>org.eclipse.jdt.core.javabuilder</name>
20+
<arguments>
21+
</arguments>
22+
</buildCommand>
23+
<buildCommand>
24+
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
25+
<arguments>
26+
</arguments>
27+
</buildCommand>
28+
</buildSpec>
29+
<natures>
30+
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
31+
<nature>org.eclipse.jdt.core.javanature</nature>
32+
</natures>
33+
</projectDescription>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3+
package="com.example.autofittextviewtest" android:versionCode="1"
4+
android:versionName="1.0">
5+
6+
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="19" />
7+
8+
<application android:allowBackup="true" />
9+
10+
</manifest>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# To enable ProGuard in your project, edit project.properties
2+
# to define the proguard.config property as described in that file.
3+
#
4+
# Add project specific ProGuard rules here.
5+
# By default, the flags in this file are appended to flags specified
6+
# in ${sdk.dir}/tools/proguard/proguard-android.txt
7+
# You can edit the include path and order by changing the ProGuard
8+
# include property in project.properties.
9+
#
10+
# For more details, see
11+
# http://developer.android.com/guide/developing/tools/proguard.html
12+
13+
# Add any project specific keep options here:
14+
15+
# If your project uses WebView with JS, uncomment the following
16+
# and specify the fully qualified class name to the JavaScript interface
17+
# class:
18+
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19+
# public *;
20+
#}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# This file is automatically generated by Android Tools.
2+
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3+
#
4+
# This file must be checked in Version Control Systems.
5+
#
6+
# To customize properties used by the Ant build system edit
7+
# "ant.properties", and override values to adapt the script to your
8+
# project structure.
9+
#
10+
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11+
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12+
13+
# Project target.
14+
target=android-19
15+
android.library=true
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<resources>
3+
4+
<declare-styleable name="AutoFitText">
5+
<attr name="minTextSize" format="dimension" />
6+
<attr name="maxTextSize" format="dimension" />
7+
8+
</declare-styleable>
9+
10+
</resources>
Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
package com.example.autofittextviewtest;
2+
import android.annotation.TargetApi;
3+
import android.content.Context;
4+
import android.content.res.Resources;
5+
import android.graphics.RectF;
6+
import android.os.Build;
7+
import android.text.Layout.Alignment;
8+
import android.text.StaticLayout;
9+
import android.text.TextPaint;
10+
import android.util.AttributeSet;
11+
import android.util.SparseIntArray;
12+
import android.util.TypedValue;
13+
import android.widget.TextView;
14+
15+
/**
16+
* a textView that is able to self-adjust its font size depending on the min and max size of the font, and its own size.<br/>
17+
* code is heavily based on this StackOverflow thread:
18+
* http://stackoverflow.com/questions/16017165/auto-fit-textview-for-android/21851239#21851239 <br/>
19+
* It should work fine with most Android versions, but might have some issues on Android 3.1 - 4.04, as setTextSize will only work for the first time. <br/>
20+
* More info here: https://code.google.com/p/android/issues/detail?id=22493 and here in case you wish to fix it: http://stackoverflow.com/a/21851239/878126
21+
*/
22+
public class AutoResizeTextView extends TextView
23+
{
24+
private static final int NO_LINE_LIMIT =-1;
25+
private final RectF mAvailableSpaceRect =new RectF();
26+
private final SparseIntArray mTextCachedSizes =new SparseIntArray();
27+
private float mMaxTextSize;
28+
private float mSpacingMult =1.0f;
29+
private float mSpacingAdd =0.0f;
30+
private float mMinTextSize =20;
31+
private int mWidthLimit;
32+
private int mMaxLines;
33+
private boolean mEnableSizeCache =true;
34+
private final SizeTester mSizeTester;
35+
private boolean mInitiallized =false;
36+
37+
private interface SizeTester
38+
{
39+
/**
40+
* @param suggestedSize
41+
* Size of text to be tested
42+
* @param availableSpace
43+
* available space in which text must fit
44+
* @return an integer < 0 if after applying {@code suggestedSize} to
45+
* text, it takes less space than {@code availableSpace}, > 0
46+
* otherwise
47+
*/
48+
public int onTestSize(int suggestedSize,RectF availableSpace);
49+
}
50+
51+
public AutoResizeTextView(final Context context)
52+
{
53+
this(context,null,0);
54+
}
55+
56+
public AutoResizeTextView(final Context context,final AttributeSet attrs)
57+
{
58+
this(context,attrs,0);
59+
}
60+
61+
public AutoResizeTextView(final Context context,final AttributeSet attrs,final int defStyle)
62+
{
63+
super(context,attrs,defStyle);
64+
mMaxTextSize=getTextSize();
65+
if(mMaxLines==0)
66+
// no value was assigned during construction
67+
mMaxLines=NO_LINE_LIMIT;
68+
// prepare size tester:
69+
final TextPaint paint=new TextPaint(getPaint());
70+
mSizeTester=new SizeTester()
71+
{
72+
final RectF textRect =new RectF();
73+
74+
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
75+
@Override
76+
public int onTestSize(final int suggestedSize,final RectF availableSPace)
77+
{
78+
paint.setTextSize(suggestedSize);
79+
final String text=getText().toString();
80+
final boolean singleline=getMaxLines()==1;
81+
if(singleline)
82+
{
83+
textRect.bottom=paint.getFontSpacing();
84+
textRect.right=paint.measureText(text);
85+
}
86+
else
87+
{
88+
final StaticLayout layout=new StaticLayout(text,paint,mWidthLimit,Alignment.ALIGN_NORMAL,mSpacingMult,mSpacingAdd,true);
89+
// return early if we have more lines
90+
if(getMaxLines()!=NO_LINE_LIMIT&&layout.getLineCount()>getMaxLines())
91+
return 1;
92+
textRect.bottom=layout.getHeight();
93+
int maxWidth=-1;
94+
for(int i=0;i<layout.getLineCount();i++)
95+
if(maxWidth<layout.getLineWidth(i))
96+
maxWidth=(int)layout.getLineWidth(i);
97+
textRect.right=maxWidth;
98+
}
99+
textRect.offsetTo(0,0);
100+
if(availableSPace.contains(textRect))
101+
// may be too small, don't worry we will find the best match
102+
return -1;
103+
// else, too big
104+
return 1;
105+
}
106+
};
107+
mInitiallized=true;
108+
}
109+
110+
@Override
111+
public void setTextSize(final float size)
112+
{
113+
mMaxTextSize=size;
114+
mTextCachedSizes.clear();
115+
adjustTextSize();
116+
}
117+
118+
@Override
119+
public void setMaxLines(final int maxlines)
120+
{
121+
super.setMaxLines(maxlines);
122+
mMaxLines=maxlines;
123+
reAdjust();
124+
}
125+
126+
@Override
127+
public int getMaxLines()
128+
{
129+
return mMaxLines;
130+
}
131+
132+
@Override
133+
public void setSingleLine()
134+
{
135+
super.setSingleLine();
136+
mMaxLines=1;
137+
reAdjust();
138+
}
139+
140+
@Override
141+
public void setSingleLine(final boolean singleLine)
142+
{
143+
super.setSingleLine(singleLine);
144+
if(singleLine)
145+
mMaxLines=1;
146+
else mMaxLines=NO_LINE_LIMIT;
147+
reAdjust();
148+
}
149+
150+
@Override
151+
public void setLines(final int lines)
152+
{
153+
super.setLines(lines);
154+
mMaxLines=lines;
155+
reAdjust();
156+
}
157+
158+
@Override
159+
public void setTextSize(final int unit,final float size)
160+
{
161+
final Context c=getContext();
162+
Resources r;
163+
if(c==null)
164+
r=Resources.getSystem();
165+
else r=c.getResources();
166+
mMaxTextSize=TypedValue.applyDimension(unit,size,r.getDisplayMetrics());
167+
mTextCachedSizes.clear();
168+
adjustTextSize();
169+
}
170+
171+
@Override
172+
public void setLineSpacing(final float add,final float mult)
173+
{
174+
super.setLineSpacing(add,mult);
175+
mSpacingMult=mult;
176+
mSpacingAdd=add;
177+
}
178+
179+
/**
180+
* Set the lower text size limit and invalidate the view
181+
*
182+
* @param minTextSize
183+
*/
184+
public void setMinTextSize(final float minTextSize)
185+
{
186+
mMinTextSize=minTextSize;
187+
reAdjust();
188+
}
189+
190+
private void reAdjust()
191+
{
192+
adjustTextSize();
193+
}
194+
195+
private void adjustTextSize()
196+
{
197+
if(!mInitiallized)
198+
return;
199+
final int startSize=(int)mMinTextSize;
200+
final int heightLimit=getMeasuredHeight()-getCompoundPaddingBottom()-getCompoundPaddingTop();
201+
mWidthLimit=getMeasuredWidth()-getCompoundPaddingLeft()-getCompoundPaddingRight();
202+
mAvailableSpaceRect.right=mWidthLimit;
203+
mAvailableSpaceRect.bottom=heightLimit;
204+
super.setTextSize(TypedValue.COMPLEX_UNIT_PX,efficientTextSizeSearch(startSize,(int)mMaxTextSize,mSizeTester,mAvailableSpaceRect));
205+
}
206+
207+
/**
208+
* Enables or disables size caching, enabling it will improve performance
209+
* where you are animating a value inside TextView. This stores the font
210+
* size against getText().length() Be careful though while enabling it as 0
211+
* takes more space than 1 on some fonts and so on.
212+
*
213+
* @param enable
214+
* enable font size caching
215+
*/
216+
public void setEnableSizeCache(final boolean enable)
217+
{
218+
mEnableSizeCache=enable;
219+
mTextCachedSizes.clear();
220+
adjustTextSize();
221+
}
222+
223+
private int efficientTextSizeSearch(final int start,final int end,final SizeTester sizeTester,final RectF availableSpace)
224+
{
225+
if(!mEnableSizeCache)
226+
return binarySearch(start,end,sizeTester,availableSpace);
227+
final String text=getText().toString();
228+
final int key=text==null ? 0 : text.length();
229+
int size=mTextCachedSizes.get(key);
230+
if(size!=0)
231+
return size;
232+
size=binarySearch(start,end,sizeTester,availableSpace);
233+
mTextCachedSizes.put(key,size);
234+
return size;
235+
}
236+
237+
private int binarySearch(final int start,final int end,final SizeTester sizeTester,final RectF availableSpace)
238+
{
239+
int lastBest=start;
240+
int lo=start;
241+
int hi=end-1;
242+
int mid=0;
243+
while(lo<=hi)
244+
{
245+
mid=lo+hi>>>1;
246+
final int midValCmp=sizeTester.onTestSize(mid,availableSpace);
247+
if(midValCmp<0)
248+
{
249+
lastBest=lo;
250+
lo=mid+1;
251+
}
252+
else if(midValCmp>0)
253+
{
254+
hi=mid-1;
255+
lastBest=hi;
256+
}
257+
else return mid;
258+
}
259+
// make sure to return last best
260+
// this is what should always be returned
261+
return lastBest;
262+
}
263+
264+
@Override
265+
protected void onTextChanged(final CharSequence text,final int start,final int before,final int after)
266+
{
267+
super.onTextChanged(text,start,before,after);
268+
reAdjust();
269+
}
270+
271+
@Override
272+
protected void onSizeChanged(final int width,final int height,final int oldwidth,final int oldheight)
273+
{
274+
mTextCachedSizes.clear();
275+
super.onSizeChanged(width,height,oldwidth,oldheight);
276+
if(width!=oldwidth||height!=oldheight)
277+
reAdjust();
278+
}
279+
}

AutoFitTextViewSample/.classpath

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<classpath>
3+
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
4+
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
5+
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
6+
<classpathentry kind="src" path="gen"/>
7+
<classpathentry kind="src" path="src"/>
8+
<classpathentry kind="output" path="bin/classes"/>
9+
</classpath>

0 commit comments

Comments
 (0)