Using auto resize to fit EditText in Android

UPDATE: [I’ve created lib project on gitHub]

Having the need of auto resizable EditText usage in Android is certainly something you’ll come across creating interactive applications at some point. I came to that point and to me it seemed that somebody has to have developed this custom widget/library and put it somewhere (gitHub) for reutilization. Partially, I was right, but it turned out that most of the solutions that are out there, need(ed) fixing, changing and a lot of customization (which takes a lot of time and I don’t advise doing, because it can consume as much time as starting from scratch).

First of all, let me say that there’s no “EditText” auto resize widgets and all of them extend TextView, which won’t be an issue since EditText extends TextView, right? Wrong. And I’ll get back at this later. Some of the best/worth mentioning AutoResize libs/widgets:
1) AndroidDeveloperLB/AutoFitTextView
2) skimarxall/RealTextView (editText widget is included in the lib)
3) danclarke/AutoResizeTextView
4) lucamtudor/AutoResizeTextView
5) grantland/android-autofittextview

The stackoverflow question that tracks this issue of auto-resizing TextView (EditText) is here. It seems that android-developer has aggregated all the possible approaches, ideas and concepts in order to tackle this issue most efficiently (I suggest you read the post and go through it before you continue reading). As a result of this AndroidDeveloperLB/AutoFitTextView lib/widget was created and I’ll discuss only this solution since I think is the most complete. If you’re willing you can try the others, most of the things here should apply to them also.

You start off by changing the extend class from TextView to EditText. For those of you that are lazy to do this, here is copy-paste:

 

public class AutoResizeEditText extends EditText {
    private static final int NO_LINE_LIMIT = -1;
    private final RectF _availableSpaceRect = new RectF();
    private final SparseIntArray _textCachedSizes = new SparseIntArray();
    private final SizeTester _sizeTester;
    private float _maxTextSize;
    private float _spacingMult = 1.0f;
    private float _spacingAdd = 0.0f;
    private float _minTextSize;
    private int _widthLimit;
    private int _maxLines;
    private boolean _enableSizeCache = true;
    private boolean _initiallized = false;
    private TextPaint paint;

    private interface SizeTester {
        /**
         * AutoResizeEditText
         *
         * @param suggestedSize
         *            Size of text to be tested
         * @param availableSpace
         *            available space in which text must fit
         * @return an integer < 0 if after applying {@code suggestedSize} to
         *         text, it takes less space than {@code availableSpace}, > 0
         *         otherwise
         */
        public int onTestSize(int suggestedSize, RectF availableSpace);
    }

    public AutoResizeEditText(final Context context) {
        this(context, null, 0);
    }

    public AutoResizeEditText(final Context context, final AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public AutoResizeEditText(final Context context, final AttributeSet attrs,
            final int defStyle) {
        super(context, attrs, defStyle);
        // using the minimal recommended font size
        _minTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
                12, getResources().getDisplayMetrics());
        _maxTextSize = getTextSize();
        if (_maxLines == 0)
            // no value was assigned during construction
            _maxLines = NO_LINE_LIMIT;
        // prepare size tester:
        _sizeTester = new SizeTester() {
            final RectF textRect = new RectF();

            @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
            @Override
            public int onTestSize(final int suggestedSize,
                    final RectF availableSPace) {
                paint.setTextSize(suggestedSize);
                final String text = getText().toString();
                final boolean singleline = getMaxLines() == 1;
                if (singleline) {
                    textRect.bottom = paint.getFontSpacing();
                    textRect.right = paint.measureText(text);
                } else {
                    final StaticLayout layout = new StaticLayout(text, paint,
                            _widthLimit, Alignment.ALIGN_NORMAL, _spacingMult,
                            _spacingAdd, true);
                    // return early if we have more lines
                    Log.d("NLN", "Current Lines = "+Integer.toString(layout.getLineCount()));
                    Log.d("NLN", "Max Lines = "+Integer.toString(getMaxLines()));
                    if (getMaxLines() != NO_LINE_LIMIT
                            && layout.getLineCount() > getMaxLines())
                        return 1;
                    textRect.bottom = layout.getHeight();
                    int maxWidth = -1;
                    for (int i = 0; i < layout.getLineCount(); i++)
                        if (maxWidth < layout.getLineWidth(i))
                            maxWidth = (int) layout.getLineWidth(i);
                    textRect.right = maxWidth;
                }
                textRect.offsetTo(0, 0);
                if (availableSPace.contains(textRect))
                    // may be too small, don't worry we will find the best match
                    return -1;
                // else, too big
                return 1;
            }
        };
        _initiallized = true;
    }

    @Override
    public void setTypeface(final Typeface tf) {
        if (paint == null)
            paint = new TextPaint(getPaint());
        paint.setTypeface(tf);
        super.setTypeface(tf);
    }

    @Override
    public void setTextSize(final float size) {
        _maxTextSize = size;
        _textCachedSizes.clear();
        adjustTextSize();
    }

    @Override
    public void setMaxLines(final int maxlines) {
        super.setMaxLines(maxlines);
        _maxLines = maxlines;
        reAdjust();
    }

    @Override
    public int getMaxLines() {
        return _maxLines;
    }

    @Override
    public void setSingleLine() {
        super.setSingleLine();
        _maxLines = 1;
        reAdjust();
    }

    @Override
    public void setSingleLine(final boolean singleLine) {
        super.setSingleLine(singleLine);
        if (singleLine)
            _maxLines = 1;
        else
            _maxLines = NO_LINE_LIMIT;
        reAdjust();
    }

    @Override
    public void setLines(final int lines) {
        super.setLines(lines);
        _maxLines = lines;
        reAdjust();
    }

    @Override
    public void setTextSize(final int unit, final float size) {
        final Context c = getContext();
        Resources r;
        if (c == null)
            r = Resources.getSystem();
        else
            r = c.getResources();
        _maxTextSize = TypedValue.applyDimension(unit, size,
                r.getDisplayMetrics());
        _textCachedSizes.clear();
        adjustTextSize();
    }

    @Override
    public void setLineSpacing(final float add, final float mult) {
        super.setLineSpacing(add, mult);
        _spacingMult = mult;
        _spacingAdd = add;
    }

    /**
     * Set the lower text size limit and invalidate the view
     *
     * @param 

     */
    public void setMinTextSize(final float minTextSize) {
        _minTextSize = minTextSize;
        reAdjust();
    }

    private void reAdjust() {
        adjustTextSize();
    }

    private void adjustTextSize() {
        if (!_initiallized)
            return;
        final int startSize = (int) _minTextSize;
        final int heightLimit = getMeasuredHeight()
                - getCompoundPaddingBottom() - getCompoundPaddingTop();
        _widthLimit = getMeasuredWidth() - getCompoundPaddingLeft()
                - getCompoundPaddingRight();
        if (_widthLimit <= 0)
            return;
        _availableSpaceRect.right = _widthLimit;
        _availableSpaceRect.bottom = heightLimit;
        super.setTextSize(
                TypedValue.COMPLEX_UNIT_PX,
                efficientTextSizeSearch(startSize, (int) _maxTextSize,
                        _sizeTester, _availableSpaceRect));
    }

    /**
     * Enables or disables size caching, enabling it will improve performance
     * where you are animating a value inside TextView. This stores the font
     * size against getText().length() Be careful though while enabling it as 0
     * takes more space than 1 on some fonts and so on.
     *
     * @param enable
     *            enable font size caching
     */
    public void setEnableSizeCache(final boolean enable) {
        _enableSizeCache = enable;
        _textCachedSizes.clear();
        adjustTextSize();
    }

    private int efficientTextSizeSearch(final int start, final int end,
            final SizeTester sizeTester, final RectF availableSpace) {
        if (!_enableSizeCache)
            return binarySearch(start, end, sizeTester, availableSpace);
        final String text = getText().toString();
        final int key = text == null ? 0 : text.length();
        int size = _textCachedSizes.get(key);
        if (size != 0)
            return size;
        size = binarySearch(start, end, sizeTester, availableSpace);
        _textCachedSizes.put(key, size);
        return size;
    }

    private int binarySearch(final int start, final int end,
            final SizeTester sizeTester, final RectF availableSpace) {
        int lastBest = start;
        int lo = start;
        int hi = end - 1;
        int mid = 0;
        while (lo <= hi) {
            mid = lo + hi >>> 1;
            final int midValCmp = sizeTester.onTestSize(mid, availableSpace);
            if (midValCmp < 0) {
                lastBest = lo;
                lo = mid + 1;
            } else if (midValCmp > 0) {
                hi = mid - 1;
                lastBest = hi;
            } else
                return mid;
        }
        // make sure to return last best
        // this is what should always be returned
        return lastBest;
    }

    @Override
    protected void onTextChanged(final CharSequence text, final int start,
            final int before, final int after) {
        super.onTextChanged(text, start, before, after);
        reAdjust();
    }

    @Override
    protected void onSizeChanged(final int width, final int height,
            final int oldwidth, final int oldheight) {
        _textCachedSizes.clear();
        super.onSizeChanged(width, height, oldwidth, oldheight);
        if (width != oldwidth || height != oldheight)
            reAdjust();
    }
}

 

Needless to say, you need to import this in your project. Put the newly imported widget in xml (add values for maxLines, maxLength in order to make the fitting more precise) and reference it in your Activity/Fragment as follows:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:real="http://schemas.android.com/apk/res-auto"
    android:id="@+id/rlRoot"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.testapplication.MainActivity" >

    <FrameLayout
        android:id="@+id/container"
        android:layout_width="500dp"
        android:layout_height="333dp"
        android:layout_centerInParent="true"
        android:background="#ffff0000" >

        <com.example.autofit.et.AutoResizeEditText
            android:id="@+id/rET"
            android:layout_height="match_parent"
            android:layout_width="match_parent"
            android:background="#FF00FF"
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:gravity="center_vertical|center_horizontal"
            android:hint="HINT"
            android:isScrollContainer="false"
            android:inputType="textMultiLine|textNoSuggestions"
            android:maxLength="240"
            android:textColor="#000000"
            android:textSize="90sp" />
    </FrameLayout>

</RelativeLayout>

 

public class MainActivity extends Activity {

    private AutoResizeEditText mAutoResizeEditText;
    

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
mAutoResizeEditText = (AutoResizeEditText) findViewById(R.id.rET);
        
                
        
    }
    
    @Override
    protected void onResume() {
        super.onResume();

    }

 

When you run the application you might not be able to click on the EditText, i.e. it behaves as TextView. Now coming back to the part that I mentioned in the beginning, in order to fix this, you MUST provide this lines in your xml declaration of the file:

android:focusable="true"
android:focusableInTouchMode="true"

It seems that we’re done and everything should work fine, but this s*it happens:doesntWork1 doesntWork2doesntWork3doesntWork4

Text is not in bounds and pressing new line seems to distort the expected behavior. There are a lot of possible limitations in order to set bounds (maxLines, maxLength, maxTextSize, maxHeight) to the text and stop this aberrant behavior, yet most of them doesn’t seem to work. After long hours spent on this and a lot of cup of coffees, this is what I think works best. The CRUCIAL FIX is anchoring your logic on maxHeight by adding the following lines after the widget reference:

mAutoResizeEditText = (AutoResizeEditText) findViewById(R.id.rET);
        mAutoResizeEditText.setEnabled(true);
        mAutoResizeEditText.setFocusableInTouchMode(true);
        mAutoResizeEditText.setFocusable(true);
        mAutoResizeEditText.setEnableSizeCache(false);
        mAutoResizeEditText.setMovementMethod(null);
        // can be added after layout inflation; it doesn't have to be fixed
        // value
        mAutoResizeEditText.setMaxHeight(330);

 

BONUS. To make things look slick (soft keys disappear if you tap outside the EditText container; also if font size is too small due to a lot of empty new lines, the EditText string is trimmed) add this code:

@Override
    protected void onResume() {
        super.onResume();
        setupUI(findViewById(R.id.rlRoot), mAutoResizeEditText);

    }

 

Where setupUI is defined in the following manner:

public void setupUI(View view, final AutoResizeEditText aText) {

        // if the view is not instance of AutoResizeEditText
        // i.e. if the user taps outside of the box
        if (!(view instanceof AutoResizeEditText)) {

            view.setOnTouchListener(new OnTouchListener() {
                
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                     hideSoftKeyboard();

                        Log.d("TXTS",
                                "Text Size = "
                                        + aText.getTextSize());
                        if (aText.getTextSize() < 50f) {
                            // you can define your minSize, in this case is 50f
                            // trim all the new lines and set the text as it was
                            // before
                            aText.setText(aText.getText().toString().replaceAll("(?m)^[ \t]*\r?\n", ""));
                        }

                        return false;
                }
            });
        }

        // If a layout container, iterate over children and seed recursion.
        if (view instanceof ViewGroup) {
            for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
                View innerView = ((ViewGroup) view).getChildAt(i);
                setupUI(innerView, aText);
            }
        }
    }

    public void hideSoftKeyboard() {
        InputMethodManager inputMethodManager = (InputMethodManager) this
                .getSystemService(Activity.INPUT_METHOD_SERVICE);
        if (this.getCurrentFocus() != null
                && this.getCurrentFocus().getWindowToken() != null)
            inputMethodManager.hideSoftInputFromWindow(this
                    .getCurrentFocus().getWindowToken(), 0);
    }

 

Result:

works1works2works3

If you have any questions or suggestions, feel free to use the comments section of the blog post or hit me up.
P.S. The videos were recorder using Recordable.

About viksaaskool

What about me?
This entry was posted in AndroidDev, snippet, tutorial and tagged , , , . Bookmark the permalink.

17 Responses to Using auto resize to fit EditText in Android

  1. Nicolas says:

    Hey, nice workaround here that saved most of my day.
    I only have a problem when I want to zoom the view before entering text (simple ScaleAnimation).
    The problem is as follow :
    When I type text in the zoomed view, the last characters of each line don’t show up (even if it seems working fne, i.e typing the few last characters of the line will create a new line etc…).
    But when I zoom out, the editText appears correct, and we can see all the characters.

    It seems like the “right limit” of the edittext is not changed when zoomed or translated, because characters seem to disappear after this “line” that would have been the “right limit” of the non-zoomed editText.

    Did you ever come accross this problem? Any idea where it could come from?

    Thanks!

    • viksaaskool says:

      I’m glad I saved most of your day 🙂
      As your problem goes, I’ve never tried the interactions you describe in combination with the AutoResizeEditText. It might be due to MotionEvent and
      mAutoResizeEditText.setFocusableInTouchMode(true);
      mAutoResizeEditText.setFocusable(true);
      That’s where I’d look first if I were you. Also, try to change the zooming (scaling) approach. how does it behave when is ordinary EditText? and so on…

      Send me code (and gif) I might take a look (not promising).

      • Nicolas says:

        Ok, sorry for the delay, I’ve been doing more testing to be able to better understand what could cause the problem.
        Here are 2 gifs :

        First one ( http://giphy.com/gifs/xTiTnH1hyuJzjnDl6w ) is the expected behaviour, tested on a Nexus5 API 21.
        Second one ( http://giphy.com/gifs/3-1-2-3o85xDB4Wyve1jh0XK ), tested on a Nexus6 API 22 shows the problem : when the EditText is zoomed, it seems that it keeps an older version of the available space or so, and so truncates what we can see on the screen. But as soon as the textSize changes or we dezoom, the text becomes good again.

        Finally, nothing much to say about the zoom itself, it’s just a basic ScaleAnimation on the parent Layout, that works without any problem with any other view / EditText.

        Please let me know if you need anything else.

        Cheers!

      • viksaaskool says:

        have you tried forcefully invalidating the AutroResizeEditText?

        I’ll have a look into it, in the meantime, post this as stackoverflow question, put some code and the gifs.

    • Nicolas says:

      Hey, couldn’t answer your last comment, but anyway, here’s the SO thread, in case you came up with something or see if anyone’s posting something that could help :
      http://stackoverflow.com/q/29370726/4706693

  2. Tanapruk says:

    Thank you. It is very useful to me.

  3. Khac Pham says:

    thank you! It’s useful. But your EditText still auto break if text too long. And I improve it. It may helpful for someone:
    public class AutoResizeEditText extends EditText {
    private static final int NO_LINE_LIMIT = -1;
    private final RectF _availableSpaceRect = new RectF();
    private final SparseIntArray _textCachedSizes = new SparseIntArray();
    private final SizeTester _sizeTester;
    private float _maxTextSize;
    private float _spacingMult = 1.0f;
    private float _spacingAdd = 0.0f;
    private float _minTextSize;
    private int _widthLimit;
    private int _maxLines;
    private boolean _enableSizeCache = true;
    private boolean _initiallized = false;
    private TextPaint paint;

    private interface SizeTester {
    /**
    * AutoResizeEditText
    *
    * @param suggestedSize Size of text to be tested
    * @param availableSpace available space in which text must fit
    * @return an integer 0
    * otherwise
    */
    int onTestSize(int suggestedSize, RectF availableSpace);
    }

    public AutoResizeEditText(final Context context) {
    this(context, null, 0);
    }

    public AutoResizeEditText(final Context context, final AttributeSet attrs) {
    this(context, attrs, 0);
    }

    public AutoResizeEditText(final Context context, final AttributeSet attrs,
    final int defStyle) {
    super(context, attrs, defStyle);
    // using the minimal recommended font size
    _minTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
    12, getResources().getDisplayMetrics());
    _maxTextSize = getTextSize();
    if (_maxLines == 0)
    // no value was assigned during construction
    _maxLines = NO_LINE_LIMIT;
    // prepare size tester:
    _sizeTester = new SizeTester() {
    final RectF textRect = new RectF();

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    @Override
    public int onTestSize(final int suggestedSize, final RectF availableSPace) {
    paint.setTextSize(suggestedSize);
    final String text = getText().toString();
    final boolean singleline = getMaxLines() == 1;
    if (singleline) {
    textRect.bottom = paint.getFontSpacing();
    textRect.right = paint.measureText(text);
    } else {
    final StaticLayout layout = new StaticLayout(text, paint, _widthLimit, Layout.Alignment.ALIGN_NORMAL, _spacingMult, _spacingAdd, true);
    // return early if we have more lines
    Log.d(“NLN”, “Current Lines = ” + Integer.toString(layout.getLineCount()));
    Log.d(“NLN”, “Max Lines = ” + Integer.toString(getMaxLines()));
    if (getMaxLines() != NO_LINE_LIMIT && layout.getLineCount() > getMaxLines())
    return 1;
    textRect.bottom = layout.getHeight();
    int maxWidth = -1;
    for (int i = 0; i < layout.getLineCount(); i++)
    if (maxWidth < layout.getLineWidth(i)) {
    maxWidth = (int) layout.getLineWidth(i);
    }
    textRect.right = maxWidth;
    }
    textRect.offsetTo(0, 0);
    if (availableSPace.contains(textRect))
    // may be too small, don't worry we will find the best match
    return -1;
    // else, too big
    return 1;
    }
    };
    _initiallized = true;
    }

    @Override
    public void setTypeface(final Typeface tf) {
    if (paint == null)
    paint = new TextPaint(getPaint());
    paint.setTypeface(tf);
    super.setTypeface(tf);
    }

    @Override
    public void setTextSize(final float size) {
    _maxTextSize = size;
    _textCachedSizes.clear();
    adjustTextSize();
    }

    @Override
    public void setMaxLines(final int maxlines) {
    super.setMaxLines(maxlines);
    _maxLines = maxlines;
    reAdjust();
    }

    @Override
    public int getMaxLines() {
    return _maxLines;
    }

    @Override
    public void setSingleLine() {
    super.setSingleLine();
    _maxLines = 1;
    reAdjust();
    }

    @Override
    public void setSingleLine(final boolean singleLine) {
    super.setSingleLine(singleLine);
    if (singleLine)
    _maxLines = 1;
    else
    _maxLines = NO_LINE_LIMIT;
    reAdjust();
    }

    @Override
    public void setLines(final int lines) {
    super.setLines(lines);
    _maxLines = lines;
    reAdjust();
    }

    @Override
    public void setTextSize(final int unit, final float size) {
    final Context c = getContext();
    Resources r;
    if (c == null)
    r = Resources.getSystem();
    else
    r = c.getResources();
    _maxTextSize = TypedValue.applyDimension(unit, size, r.getDisplayMetrics());
    _textCachedSizes.clear();
    adjustTextSize();
    }

    @Override
    public void setLineSpacing(final float add, final float mult) {
    super.setLineSpacing(add, mult);
    _spacingMult = mult;
    _spacingAdd = add;
    }

    /**
    * Set the lower text size limit and invalidate the view
    *
    * @param
    */
    public void setMinTextSize(final float minTextSize) {
    _minTextSize = minTextSize;
    reAdjust();
    }

    public void reAdjust() {
    if(isCJK(getText().toString())){
    adjustTextSize();
    return;
    }

    // step 1: find font A that fit all-text in text view.
    adjustTextSize();
    // step 2: find longest line
    ArrayList arrayLines = trimTextToLines();

    String longestText = “”;
    for(String line: arrayLines){
    float longWidth = getPaint().measureText(longestText);
    float textWidth = getPaint().measureText(line);
    if(longWidth<textWidth){
    longestText = line;
    }
    }

    // step 3: find text size fit longest line
    detectSizeWithLongText(longestText);
    }

    private ArrayList trimTextToLines(){
    if(_widthLimit==0){
    return new ArrayList();
    }
    TextPaint textPaint = new TextPaint(getPaint());
    String longestText = getText().toString().replaceAll(“\n”, ” “);
    String[] tokens = longestText.split(” “);

    StaticLayout layout = new StaticLayout(longestText,textPaint,_widthLimit,Layout.Alignment.ALIGN_NORMAL, _spacingMult, _spacingAdd, true);

    float thresold = 1.2f;
    float preLineCountFloor = (float)Math.floor(Math.sqrt(layout.getWidth()/layout.getHeight()))/thresold;
    float properWidthFloor = layout.getWidth()*preLineCountFloor;

    ArrayList arrayLines = new ArrayList();
    arrayLines.add(“”);
    int index = 0;
    for(String token: tokens){
    String newString = “”;
    // join token to current line
    if(TextUtils.isEmpty(arrayLines.get(index))){
    newString = token;
    }else{
    newString = arrayLines.get(index)+” “+token;
    }
    // Detect if current-line-width is higher than properWidthFloor
    float currentWidth = textPaint.measureText(newString);
    if(currentWidth>properWidthFloor && !TextUtils.isEmpty(arrayLines.get(index))){
    arrayLines.add(token);
    index++;
    }
    else{
    arrayLines.set(index,newString);
    }
    }
    return arrayLines;
    }

    private void detectSizeWithLongText(String longText){
    Log.e(“MEGATEXT”, String.format(“longtext:%s”, longText));
    if(TextUtils.isEmpty(longText)){
    return;
    }
    TextPaint tp = new TextPaint(getPaint());
    tp.setTextSize(_maxTextSize);
    float textSize = tp.getTextSize();
    int _widthLimit = getMeasuredWidth() – getCompoundPaddingLeft() – getCompoundPaddingRight();

    tp.setTextSize(textSize);
    StaticLayout layout = new StaticLayout(“M”+longText+”M”, tp, _widthLimit, Layout.Alignment.ALIGN_NORMAL, _spacingMult, _spacingAdd, true);
    while(layout.getLineCount()>1){
    textSize–;
    tp.setTextSize(textSize);
    layout = new StaticLayout(“M”+longText+”M”, tp, _widthLimit, Layout.Alignment.ALIGN_NORMAL, _spacingMult, _spacingAdd, true);
    }
    super.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
    }

    private void adjustTextSize() {
    if (!_initiallized)
    return;
    final int startSize = (int) _minTextSize;
    final int heightLimit = getMeasuredHeight() – getCompoundPaddingBottom() – getCompoundPaddingTop();
    _widthLimit = getMeasuredWidth() – getCompoundPaddingLeft() – getCompoundPaddingRight();
    if (_widthLimit <= 0)
    return;
    _availableSpaceRect.right = _widthLimit;
    _availableSpaceRect.bottom = heightLimit;
    super.setTextSize(TypedValue.COMPLEX_UNIT_PX, efficientTextSizeSearch(startSize, (int) _maxTextSize, _sizeTester, _availableSpaceRect));
    }

    /**
    * Enables or disables size caching, enabling it will improve performance
    * where you are animating a value inside TextView. This stores the font
    * size against getText().length() Be careful though while enabling it as 0
    * takes more space than 1 on some fonts and so on.
    *
    * @param enable enable font size caching
    */
    public void setEnableSizeCache(final boolean enable) {
    _enableSizeCache = enable;
    _textCachedSizes.clear();
    adjustTextSize();
    }

    private int efficientTextSizeSearch(final int start, final int end, final SizeTester sizeTester, final RectF availableSpace) {
    if (!_enableSizeCache)
    return binarySearch(start, end, sizeTester, availableSpace);
    final String text = getText().toString();
    final int key = text == null ? 0 : text.length();
    int size = _textCachedSizes.get(key);
    if (size != 0)
    return size;
    size = binarySearch(start, end, sizeTester, availableSpace);
    _textCachedSizes.put(key, size);
    return size;
    }

    private int binarySearch(final int start, final int end,
    final SizeTester sizeTester, final RectF availableSpace) {
    int lastBest = start;
    int lo = start;
    int hi = end – 1;
    int mid = 0;
    while (lo >> 1;
    final int midValCmp = sizeTester.onTestSize(mid, availableSpace);
    if (midValCmp 0) {
    hi = mid – 1;
    lastBest = hi;
    } else
    return mid;
    }
    // make sure to return last best
    // this is what should always be returned
    return lastBest;
    }

    @Override
    protected void onTextChanged(final CharSequence text, final int start, final int before, final int after) {
    super.onTextChanged(text, start, before, after);
    reAdjust();
    }

    @Override
    protected void onSizeChanged(final int width, final int height,
    final int oldwidth, final int oldheight) {
    _textCachedSizes.clear();
    super.onSizeChanged(width, height, oldwidth, oldheight);
    if (width != oldwidth || height != oldheight)
    reAdjust();
    }

    /**
    * check str contains CJK char or not.
    * */
    public static boolean isCJK(String str){
    int length = str.length();
    for (int i = 0; i < length; i++){
    char ch = str.charAt(i);
    if (isCJK(ch)){
    return true;
    }
    }
    return false;
    }

    /**
    * check ch is a CJK or not.
    * */
    public static boolean isCJK(char ch){
    Character.UnicodeBlock block = Character.UnicodeBlock.of(ch);
    return Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS.equals(block) ||
    Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS.equals(block) ||
    Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A.equals(block);
    }
    }

  4. Rao says:

    Very useful post. Have you ever tried auto re-size of “Hint”. Suppose if we have a “hint” whose size varies when localized, How do we re-size the text size to fit the “hint” inside the edit text?

  5. Jiele Ye says:

    what about the cursor?

  6. aakash shah says:

    how to drag this AutoResizeEditText view?

  7. aakash shah says:

    how to drag AutoResize EditText in frame layout ?

  8. Container Modifikasi Surabaya

  9. Asad says:

    cursor becomes invisible when using this editText

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s