title: How to autoresize textsize in TextView to fit available space vertically and horizontally?
body: <p>I would like to know if there is an easy way to autoresize the text in a textview to fit its available space (vertically and horizontally) without a linebreak or overlapping. My goal is to make the text as large as possible on any device. This should work in landscape and in portrait.</p>
  
  <p>I have it almost working (only in portrait-mode), it looks like this:</p>
  
  <p><a href="http://postimg.org/image/mt4suhagp/" rel="nofollow noreferrer">myapp in portrait</a></p>
  
  <p><strong>simplified javacode:</strong></p>
  
  <pre><code>public class MainActivity extends Activity{
  
  private TextView        mTV_veryTop;
  private TextView        mTV_top;
  private TextView        mTV_middle;
  private TextView        mTV_bottomLeft;
  private TextView        mTV_bottomRight;
  private Boolean         resized = false;
  
  @Override
  protected void onCreate(Bundle savedInstanceState)
  {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.cockpit_layout);
  
      mTV_veryTop = (TextView) findViewById(R.id.veryTop);
      mTV_top = (TextView) findViewById(R.id.top);
      mTV_middle = (TextView) findViewById(R.id.middle);
      mTV_bottomLeft = (TextView) findViewById(R.id.bottomLeft);
      mTV_bottomRight = (TextView) findViewById(R.id.bottomRight);
  
  }
  
  @Override
  public void onWindowFocusChanged(boolean hasFocus)
  {
      // TODO Auto-generated method stub
      super.onWindowFocusChanged(hasFocus);
  
      if (resized == false)
      {
  
          shrinkTextToFit(mTV_veryTop.getWidth(), mTV_veryTop, 300, 10);  
          shrinkTextToFit(mTV_top.getWidth(), mTV_top, 300, 10);  
          shrinkTextToFit(mTV_middle.getWidth(), mTV_middle, 300, 10);    
          shrinkTextToFit(mTV_bottomLeft.getWidth(),mTV_bottomLeft, 300, 10); 
          shrinkTextToFit(mTV_bottomRight.getWidth(), mTV_bottomRight, 300, 10);  
  
          resized = true;
      }
  
  }
  
  public static void shrinkTextToFit(float availableWidth, TextView textView, float startingTextSize, float minimumTextSize)
  {
  
      CharSequence text = textView.getText();
      float textSize = startingTextSize;
      textView.setTextSize(startingTextSize);
  
      while (text != (TextUtils.ellipsize(text, textView.getPaint(), availableWidth, TextUtils.TruncateAt.END)))
      {
          textSize -= 1;
          if (textSize &lt; minimumTextSize)
          {
              break;
          }
          else
          {
              textView.setTextSize(textSize);
          }
      }
  }
  </code></pre>
  
  <p>}</p>
  
  <p><strong>layout-file:</strong></p>
  
  <pre><code> &lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:tools="http://schemas.android.com/tools"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:background="#000000"
      android:orientation="vertical" &gt;
  
      &lt;TextView
          android:id="@+id/veryTop"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_gravity="center"
          android:layout_weight="1"
          android:gravity="center"
          android:text="very top"
          android:textColor="@android:color/white"
          android:textSize="500dp" &gt;
      &lt;/TextView&gt;
  
       &lt;TextView
          android:id="@+id/top"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:layout_gravity="center"
          android:layout_weight="5"
          android:gravity="center"
          android:text="top"
          android:textColor="@android:color/white"
          android:textSize="500dp" /&gt;
  
      &lt;TextView
          android:id="@+id/middle"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_gravity="center"
          android:layout_weight="1"
          android:gravity="middle"
          android:text="N.A."
          android:textColor="@android:color/white"
          android:textSize="500dp" /&gt;
  
      &lt;LinearLayout
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:layout_weight="3"
          android:orientation="horizontal" &gt;
  
  
  
          &lt;TextView
              android:id="@+id/bottomLeft"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:layout_gravity="center"
              android:layout_weight="5"
              android:gravity="center"
           android:text="bottom left"
              android:textColor="@android:color/white"
              android:textSize="500dp" &gt;
          &lt;/TextView&gt;
  
          &lt;TextView
              android:id="@+id/bottomRight"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:layout_gravity="center"
              android:layout_weight="5"
              android:gravity="center"
              android:text="bottom right"
              android:textColor="@android:color/white"
              android:textSize="500dp" &gt;
          &lt;/TextView&gt;
      &lt;/LinearLayout&gt;
  
  &lt;/LinearLayout&gt;
  </code></pre>
  
  <p>.......but this is not working in landscape and not even perfect in portrait (some pixels are missing at the bottom)</p>
  
  <p>i have read several post like these:</p>
  
  <p><a href="https://stackoverflow.com/questions/2596452/how-to-scale-resize-text-to-fit-a-textview">How to scale/resize text to fit a TextView?</a></p>
  
  <p><a href="https://stackoverflow.com/questions/5033012/auto-scale-textview-text-to-fit-within-bounds/21851157#21851157">Auto Scale TextView Text to Fit within Bounds</a></p>
  
  <p><a href="https://stackoverflow.com/questions/7259016/scale-text-in-a-view-to-fit/7259136#7259136">Scale text in a view to fit?</a></p>
  
  <p>......and tried different methods/textView classes, but there was always something that didnt work in case of my needs.</p>
  
  <p>Any help? </p>
  
  <p><strong>Update:</strong></p>
  
  <p>I dont know why my question is downvoted, since it is not easy to find a class/textview (under the "million libraries") which does all i asked for. Here is the class which does all i need (might help someone):</p>
  
  <pre><code>public class AutoResizeTextview extends TextView
  {
      private interface SizeTester
      {
          /**
           * 
           * @param suggestedSize
           *            Size of text to be tested
           * @param availableSpace
           *            available space in which text must fit
           * @return an integer &lt; 0 if after applying {@code suggestedSize} to
           *         text, it takes less space than {@code availableSpace}, &gt; 0
           *         otherwise
           */
          public int onTestSize(int suggestedSize, RectF availableSpace);
      }
  
      private RectF               mTextRect           = new RectF();
  
      private RectF               mAvailableSpaceRect;
  
      private SparseIntArray      mTextCachedSizes;
  
      private TextPaint           mPaint;
  
      private float               mMaxTextSize;
  
      private float               mSpacingMult        = 1.0f;
  
      private float               mSpacingAdd         = 0.0f;
  
      private float               mMinTextSize        = 3;
  
      private int                 mWidthLimit;
  
      private static final int    NO_LINE_LIMIT       = -1;
      private int                 mMaxLines;
  
      private boolean             mEnableSizeCache    = true;
      private boolean             mInitiallized;
  
      public AutoResizeTextview(Context context)
      {
          super(context);
          initialize();
      }
  
      public AutoResizeTextview(Context context, AttributeSet attrs)
      {
          super(context, attrs);
          initialize();
      }
  
      public AutoResizeTextview(Context context, AttributeSet attrs, int defStyle)
      {
          super(context, attrs, defStyle);
          initialize();
      }
  
      private void initialize()
      {
          mPaint = new TextPaint(getPaint());
          mMaxTextSize = getTextSize();
          mAvailableSpaceRect = new RectF();
          mTextCachedSizes = new SparseIntArray();
          if (mMaxLines == 0)
          {
              // no value was assigned during construction
              mMaxLines = NO_LINE_LIMIT;
          }
          mInitiallized = true;
      }
  
      @Override
      public void setText(final CharSequence text, BufferType type)
      {
          super.setText(text, type);
          adjustTextSize(text.toString());
      }
  
      @Override
      public void setTextSize(float size)
      {
          mMaxTextSize = size;
          mTextCachedSizes.clear();
          adjustTextSize(getText().toString());
      }
  
      @Override
      public void setMaxLines(int maxlines)
      {
          super.setMaxLines(maxlines);
          mMaxLines = maxlines;
          reAdjust();
      }
  
      public int getMaxLines()
      {
          return mMaxLines;
      }
  
      @Override
      public void setSingleLine()
      {
          super.setSingleLine();
          mMaxLines = 1;
          reAdjust();
      }
  
      @Override
      public void setSingleLine(boolean singleLine)
      {
          super.setSingleLine(singleLine);
          if (singleLine)
          {
              mMaxLines = 1;
          }
          else
          {
              mMaxLines = NO_LINE_LIMIT;
          }
          reAdjust();
      }
  
      @Override
      public void setLines(int lines)
      {
          super.setLines(lines);
          mMaxLines = lines;
          reAdjust();
      }
  
      @Override
      public void setTextSize(int unit, float size)
      {
          Context c = getContext();
          Resources r;
  
          if (c == null)
              r = Resources.getSystem();
          else
              r = c.getResources();
          mMaxTextSize = TypedValue.applyDimension(unit, size, r.getDisplayMetrics());
          mTextCachedSizes.clear();
          adjustTextSize(getText().toString());
      }
  
      @Override
      public void setLineSpacing(float add, float mult)
      {
          super.setLineSpacing(add, mult);
          mSpacingMult = mult;
          mSpacingAdd = add;
      }
  
      /**
       * Set the lower text size limit and invalidate the view
       * 
       * @param minTextSize
       */
      public void setMinTextSize(float minTextSize)
      {
          mMinTextSize = minTextSize;
          reAdjust();
      }
  
      private void reAdjust()
      {
          adjustTextSize(getText().toString());
      }
  
      private void adjustTextSize(String string)
      {
          if (!mInitiallized)
          {
              return;
          }
          int startSize = (int) mMinTextSize;
          int heightLimit = getMeasuredHeight() - getCompoundPaddingBottom() - getCompoundPaddingTop();
          mWidthLimit = getMeasuredWidth() - getCompoundPaddingLeft() - getCompoundPaddingRight();
          mAvailableSpaceRect.right = mWidthLimit;
          mAvailableSpaceRect.bottom = heightLimit;
          super.setTextSize(TypedValue.COMPLEX_UNIT_PX, efficientTextSizeSearch(startSize, (int) mMaxTextSize, mSizeTester, mAvailableSpaceRect));
      }
  
      private final SizeTester    mSizeTester = new SizeTester()
      {
          @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
          @Override
          public int onTestSize(int suggestedSize, RectF availableSPace)
          {
              mPaint.setTextSize(suggestedSize);
              String text = getText().toString();
              boolean singleline = getMaxLines() == 1;
              // if (singleline) {    //my comment-out
              // mTextRect.bottom = mPaint.getFontSpacing();  //my comment-out
              // mTextRect.right = mPaint.measureText(text);  //my comment-out
              // } else { //my comment-out
              StaticLayout layout = new StaticLayout(text, mPaint, mWidthLimit, Alignment.ALIGN_NORMAL, mSpacingMult,
                      mSpacingAdd, true);
              // return early if we have more lines
              if (getMaxLines() != NO_LINE_LIMIT &amp;&amp; layout.getLineCount() &gt; getMaxLines())
              {
                  return 1;
              }
              mTextRect.bottom = layout.getHeight();
              int maxWidth = -1;
              for (int i = 0; i &lt; layout.getLineCount(); i++)
              {
                  if (maxWidth &lt; layout.getLineWidth(i))
                  {
                      maxWidth = (int) layout.getLineWidth(i);
                  }
              }
              mTextRect.right = maxWidth;
              // }    //my comment-out
  
              mTextRect.offsetTo(0, 0);
              if (availableSPace.contains(mTextRect))
              {
                  // may be too small, don't worry we will find the best match
                  return -1;
              }
              else
              {
                  // too big
                  return 1;
              }
          }
      };
  
      /**
       * 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 enableSizeCache(boolean enable)
      {
          mEnableSizeCache = enable;
          mTextCachedSizes.clear();
          adjustTextSize(getText().toString());
      }
  
      private int efficientTextSizeSearch(int start, int end, SizeTester sizeTester, RectF availableSpace)
      {
          if (!mEnableSizeCache)
          {
              return binarySearch(start, end, sizeTester, availableSpace);
          }
          String text = getText().toString();
          int key = text == null ? 0 : text.length();
          int size = mTextCachedSizes.get(key);
          if (size != 0)
          {
              return size;
          }
          size = binarySearch(start, end, sizeTester, availableSpace);
          mTextCachedSizes.put(key, size);
          return size;
      }
  
      private static int binarySearch(int start, int end, SizeTester sizeTester, RectF availableSpace)
      {
          int lastBest = start;
          int lo = start;
          int hi = end - 1;
          int mid = 0;
          while (lo &lt;= hi)
          {
              mid = (lo + hi) &gt;&gt;&gt; 1;
              int midValCmp = sizeTester.onTestSize(mid, availableSpace);
              if (midValCmp &lt; 0)
              {
                  lastBest = lo;
                  lo = mid + 1;
              }
              else
                  if (midValCmp &gt; 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(int width, int height, int oldwidth, int oldheight)
      {
          mTextCachedSizes.clear();
          super.onSizeChanged(width, height, oldwidth, oldheight);
          if (width != oldwidth || height != oldheight)
          {
              reAdjust();
          }
      }
  }
  </code></pre>