2014-08-28 49 views
2

我想知道如果有自動調整在一個TextView文本沒有斷行或重疊,以適應其可用空間(垂直和水平方向)的簡單方法。我的目標是在任何設備上使文本儘可能大。這應該在橫向和縱向工作。如何在TextView中自動調整文本大小以垂直和水平地適應可用空間?

我有差不多的工作(僅在人像模式),它看起來像這樣:

myapp in portrait

簡化javacode:

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 < minimumTextSize) 
     { 
      break; 
     } 
     else 
     { 
      textView.setTextSize(textSize); 
     } 
    } 
} 

}

佈局-file:

<?xml version="1.0" encoding="utf-8"?> 
<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" > 

    <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" > 
    </TextView> 

    <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" /> 

    <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" /> 

    <LinearLayout 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:layout_weight="3" 
     android:orientation="horizontal" > 



     <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" > 
     </TextView> 

     <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" > 
     </TextView> 
    </LinearLayout> 

</LinearLayout> 

.......但這不是景觀工作,並在畫像甚至沒有完美的(某些像素在底部丟失)

我已看過一些帖子這樣的:

How to scale/resize text to fit a TextView?

Auto Scale TextView Text to Fit within Bounds

Scale text in a view to fit?

......並嘗試了不同的方法/ textView類,但總是有些東西在我的需要時不起作用。

任何幫助?

更新:

我不知道爲什麼我的問題是downvoted,因爲它是不容易找到一個類/ TextView的(在「萬個庫」),它做了所有我問。這裏是我需要的一切(可以幫助某人):

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 < 0 if after applying {@code suggestedSize} to 
     *   text, it takes less space than {@code availableSpace}, > 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 && layout.getLineCount() > getMaxLines()) 
      { 
       return 1; 
      } 
      mTextRect.bottom = layout.getHeight(); 
      int maxWidth = -1; 
      for (int i = 0; i < layout.getLineCount(); i++) 
      { 
       if (maxWidth < 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 <= hi) 
     { 
      mid = (lo + hi) >>> 1; 
      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(int width, int height, int oldwidth, int oldheight) 
    { 
     mTextCachedSizes.clear(); 
     super.onSizeChanged(width, height, oldwidth, oldheight); 
     if (width != oldwidth || height != oldheight) 
     { 
      reAdjust(); 
     } 
    } 
} 

回答

-1

已經有大約一百萬個圖書館提供這個功能。看看它們的實現,或者直接使用它。在谷歌

https://github.com/grantland/android-autofittextview

https://bitbucket.org/ankri/autoscaletextview/src

5秒給了我這些。

+0

謝謝r2DoesInc,我想第一個,幾乎是高興。雖然只用於肖像:我只能看到textviews「非常頂」和「中」,只有一半。試圖找出什麼導致這......可能是我的佈局文件f.i中的東西。重量....我不知道。正如所說:我嘗試過類似這樣的課程,但總是有些東西在我的需求中無法正常工作,例如:只能在風景中或僅在肖像中使用(如此一種)。 – treesoft 2014-08-28 20:33:58

+0

好吧,我想我可以說,第一個只是不考慮可用高度。所以如果我這樣做:textview.setMinTextSize(20); textview.setMaxTextSize(200);但是可用高度對於200來說不夠高,反正它適合於可用寬度。有人知道有這樣的課程嗎? – treesoft 2014-08-28 22:16:59

+0

我認爲第二個不是(從閱讀代碼) – treesoft 2014-08-28 22:20:01

相關問題