Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <RelativeLayout 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" tools:context=".MainActivity">
- <Button android:id="@+id/button1" android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:layout_centerHorizontal="true" android:text="Button" />
- <FrameLayout android:layout_width="match_parent"
- android:layout_height="wrap_content" android:layout_above="@+id/button1"
- android:layout_alignParentLeft="true" android:background="#ffff0000"
- android:layout_alignParentRight="true" android:id="@+id/container"
- android:layout_alignParentTop="true" />
- </RelativeLayout>
- public class MainActivity extends Activity
- {
- private final Random _random =new Random();
- private static final String ALLOWED_CHARACTERS ="qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890";
- @Override
- protected void onCreate(final Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- final ViewGroup container=(ViewGroup)findViewById(R.id.container);
- findViewById(R.id.button1).setOnClickListener(new OnClickListener()
- {
- @Override
- public void onClick(final View v)
- {
- container.removeAllViews();
- final int maxWidth=container.getWidth();
- final int maxHeight=container.getHeight();
- final FontFitTextView fontFitTextView=new FontFitTextView(MainActivity.this);
- final int width=_random.nextInt(maxWidth)+1;
- final int height=_random.nextInt(maxHeight)+1;
- fontFitTextView.setLayoutParams(new LayoutParams(width,height));
- fontFitTextView.setSingleLine();
- fontFitTextView.setBackgroundColor(0xff00ff00);
- final String text=getRandomText();
- fontFitTextView.setText(text);
- container.addView(fontFitTextView);
- Log.d("DEBUG","width:"+width+" height:"+height+" text:"+text);
- }
- });
- }
- private String getRandomText()
- {
- final int textLength=_random.nextInt(20)+1;
- final StringBuilder builder=new StringBuilder();
- for(int i=0;i<textLength;++i)
- builder.append(ALLOWED_CHARACTERS.charAt(_random.nextInt(ALLOWED_CHARACTERS.length())));
- return builder.toString();
- }
- }
- @Override
- protected void onCreate(final Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- final ViewGroup container = (ViewGroup) findViewById(R.id.container);
- findViewById(R.id.button1).setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(final View v) {
- container.removeAllViews();
- final int maxWidth = container.getWidth();
- final int maxHeight = container.getHeight();
- final AutoResizeTextView fontFitTextView = new AutoResizeTextView(MainActivity.this);
- final int width = _random.nextInt(maxWidth) + 1;
- final int height = _random.nextInt(maxHeight) + 1;
- fontFitTextView.setLayoutParams(new FrameLayout.LayoutParams(
- width, height));
- int maxLines = _random.nextInt(4) + 1;
- fontFitTextView.setMaxLines(maxLines);
- fontFitTextView.setTextSize(500);// max size
- fontFitTextView.enableSizeCache(false);
- fontFitTextView.setBackgroundColor(0xff00ff00);
- final String text = getRandomText();
- fontFitTextView.setText(text);
- container.addView(fontFitTextView);
- Log.d("DEBUG", "width:" + width + " height:" + height
- + " text:" + text + " maxLines:" + maxLines);
- }
- });
- }
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:padding="16dp" >
- <com.vj.widgets.AutoResizeTextView
- android:layout_width="match_parent"
- android:layout_height="100dp"
- android:ellipsize="none"
- android:maxLines="2"
- android:text="Auto Resized Text, max 2 lines"
- android:textSize="100sp" /> <!-- maximum size -->
- <com.vj.widgets.AutoResizeTextView
- android:layout_width="match_parent"
- android:layout_height="100dp"
- android:ellipsize="none"
- android:gravity="center"
- android:maxLines="1"
- android:text="Auto Resized Text, max 1 line"
- android:textSize="100sp" /> <!-- maximum size -->
- <com.vj.widgets.AutoResizeTextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="Auto Resized Text"
- android:textSize="500sp" /> <!-- maximum size -->
- </LinearLayout>
- import android.annotation.TargetApi;
- import android.content.Context;
- import android.content.res.Resources;
- import android.graphics.RectF;
- import android.os.Build;
- import android.text.Layout.Alignment;
- import android.text.StaticLayout;
- import android.text.TextPaint;
- import android.util.AttributeSet;
- import android.util.SparseIntArray;
- import android.util.TypedValue;
- import android.widget.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 = 20;
- private int mWidthLimit;
- private static final int NO_LINE_LIMIT = -1;
- private int mMaxLines;
- private boolean mEnableSizeCache = true;
- private boolean mInitializedDimens;
- 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;
- }
- }
- @Override
- public void setTextSize(float size) {
- mMaxTextSize = size;
- mTextCachedSizes.clear();
- adjustTextSize();
- }
- @Override
- public void setMaxLines(int maxlines) {
- super.setMaxLines(maxlines);
- mMaxLines = maxlines;
- adjustTextSize();
- }
- public int getMaxLines() {
- return mMaxLines;
- }
- @Override
- public void setSingleLine() {
- super.setSingleLine();
- mMaxLines = 1;
- adjustTextSize();
- }
- @Override
- public void setSingleLine(boolean singleLine) {
- super.setSingleLine(singleLine);
- if (singleLine) {
- mMaxLines = 1;
- } else {
- mMaxLines = NO_LINE_LIMIT;
- }
- adjustTextSize();
- }
- @Override
- public void setLines(int lines) {
- super.setLines(lines);
- mMaxLines = lines;
- adjustTextSize();
- }
- @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();
- }
- @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;
- adjustTextSize();
- }
- private void adjustTextSize() {
- if (!mInitializedDimens) {
- 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) {
- mTextRect.bottom = mPaint.getFontSpacing();
- mTextRect.right = mPaint.measureText(text);
- } else {
- 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;
- }
- 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);
- }
- int key = getText().toString().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 the 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);
- adjustTextSize();
- }
- @Override
- protected void onSizeChanged(int width, int height, int oldwidth,
- int oldheight) {
- mInitializedDimens = true;
- mTextCachedSizes.clear();
- super.onSizeChanged(width, height, oldwidth, oldheight);
- if (width != oldwidth || height != oldheight) {
- adjustTextSize();
- }
- }
- }
- private void adjustTextSize(final String text) {
- if (!mInitialized) {
- return;
- }
- int heightLimit = getMeasuredHeight() - getCompoundPaddingBottom() - getCompoundPaddingTop();
- mWidthLimit = getMeasuredWidth() - getCompoundPaddingLeft() - getCompoundPaddingRight();
- mAvailableSpaceRect.right = mWidthLimit;
- mAvailableSpaceRect.bottom = heightLimit;
- int maxTextSplits = text.split(" ").length;
- AutoResizeTextView.super.setMaxLines(Math.min(maxTextSplits, mMaxLines));
- super.setTextSize(
- TypedValue.COMPLEX_UNIT_PX,
- binarySearch((int) mMinTextSize, (int) mMaxTextSize,
- mSizeTester, mAvailableSpaceRect));
- }
- for (float testSize; (upperTextSize - lowerTextSize) > mThreshold;) {
- // Go to the mean value...
- testSize = (upperTextSize + lowerTextSize) / 2;
- // ... inflate the dummy TextView by setting a scaled textSize and the text...
- mTestView.setTextSize(TypedValue.COMPLEX_UNIT_SP, testSize / mScaledDensityFactor);
- mTestView.setText(text);
- // ... call measure to find the current values that the text WANTS to occupy
- mTestView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
- int tempHeight = mTestView.getMeasuredHeight();
- // ... decide whether those values are appropriate.
- if (tempHeight >= targetFieldHeight) {
- upperTextSize = testSize; // Font is too big, decrease upperSize
- }
- else {
- lowerTextSize = testSize; // Font is too small, increase lowerSize
- }
- }
- <com.example.myProject.AutoFitText
- android:id="@+id/textView"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="4"
- android:text="@string/LoremIpsum" />
- final Random _random = new Random();
- final String ALLOWED_CHARACTERS = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890";
- final int textLength = _random.nextInt(80) + 20;
- final StringBuilder builder = new StringBuilder();
- for (int i = 0; i < textLength; ++i) {
- if (i % 7 == 0 && i != 0) {
- builder.append(" ");
- }
- builder.append(ALLOWED_CHARACTERS.charAt(_random.nextInt(ALLOWED_CHARACTERS.length())));
- }
- ((AutoFitText) findViewById(R.id.textViewMessage)).setText(builder.toString());
- public class ScalableTextView extends TextView
- {
- float defaultTextSize = 0.0f;
- public ScalableTextView(Context context, AttributeSet attrs, int defStyle)
- {
- super(context, attrs, defStyle);
- setSingleLine();
- setEllipsize(TruncateAt.END);
- defaultTextSize = getTextSize();
- }
- public ScalableTextView(Context context, AttributeSet attrs)
- {
- super(context, attrs);
- setSingleLine();
- setEllipsize(TruncateAt.END);
- defaultTextSize = getTextSize();
- }
- public ScalableTextView(Context context)
- {
- super(context);
- setSingleLine();
- setEllipsize(TruncateAt.END);
- defaultTextSize = getTextSize();
- }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
- {
- setTextSize(TypedValue.COMPLEX_UNIT_PX, defaultTextSize);
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- final Layout layout = getLayout();
- if (layout != null)
- {
- final int lineCount = layout.getLineCount();
- if (lineCount > 0)
- {
- int ellipsisCount = layout.getEllipsisCount(lineCount - 1);
- while (ellipsisCount > 0)
- {
- final float textSize = getTextSize();
- // textSize is already expressed in pixels
- setTextSize(TypedValue.COMPLEX_UNIT_PX, (textSize - 1));
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- ellipsisCount = layout.getEllipsisCount(lineCount - 1);
- }
- }
- }
- }
- }
- final String DOUBLE_BYTE_SPACE = "u3000";
- textView.append(DOUBLE_BYTE_SPACE);
- final String DOUBLE_BYTE_SPACE = "u3000";
- AutoResizeTextView textView = (AutoResizeTextView) view.findViewById(R.id.aTextView);
- String fixString = "";
- if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB_MR1
- && android.os.Build.VERSION.SDK_INT <= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
- fixString = DOUBLE_BYTE_SPACE;
- }
- textView.setText(fixString + "The text" + fixString);
- <?xml version="1.0" encoding="utf-8"?>
- <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:foo="http://schemas.android.com/apk/res-auto"
- android:layout_width="wrap_content"
- android:layout_height="match_parent" >
- <de.meinprospekt.androidhd.view.AutoFitText
- android:layout_width="wrap_content"
- android:layout_height="10dp"
- android:text="Small Text"
- android:textColor="#FFFFFF"
- android:textSize="100sp"
- foo:customFont="fonts/Roboto-Light.ttf" />
- </FrameLayout>
- import java.util.ArrayList;
- import java.util.List;
- import android.annotation.SuppressLint;
- import android.content.Context;
- import android.content.res.TypedArray;
- import android.graphics.Paint;
- import android.graphics.Typeface;
- import android.os.Build;
- import android.util.AttributeSet;
- import android.util.Log;
- import android.util.TypedValue;
- import android.view.View;
- import android.view.ViewGroup.LayoutParams;
- import android.view.ViewTreeObserver;
- import android.view.ViewTreeObserver.OnGlobalLayoutListener;
- import android.widget.TextView;
- import de.meinprospekt.androidhd.R;
- import de.meinprospekt.androidhd.adapter.BrochuresHorizontalAdapter;
- import de.meinprospekt.androidhd.util.LOG;
- /**
- * https://stackoverflow.com/a/16174468/2075875 This class builds a new android Widget named AutoFitText which can be used instead of a TextView to
- * have the text font size in it automatically fit to match the screen width. Credits go largely to Dunni, gjpc, gregm and speedplane from
- * Stackoverflow, method has been (style-) optimized and rewritten to match android coding standards and our MBC. This version upgrades the original
- * "AutoFitTextView" to now also be adaptable to height and to accept the different TextView types (Button, TextClock etc.)
- *
- * @author pheuschk
- * @createDate: 18.04.2013
- *
- * combined with: https://stackoverflow.com/a/7197867/2075875
- */
- @SuppressWarnings("unused")
- public class AutoFitText extends TextView {
- private static final String TAG = AutoFitText.class.getSimpleName();
- /** Global min and max for text size. Remember: values are in pixels! */
- private final int MIN_TEXT_SIZE = 10;
- private final int MAX_TEXT_SIZE = 400;
- /** Flag for singleLine */
- private boolean mSingleLine = false;
- /**
- * A dummy {@link TextView} to test the text size without actually showing anything to the user
- */
- private TextView mTestView;
- /**
- * A dummy {@link Paint} to test the text size without actually showing anything to the user
- */
- private Paint mTestPaint;
- /**
- * Scaling factor for fonts. It's a method of calculating independently (!) from the actual density of the screen that is used so users have the
- * same experience on different devices. We will use DisplayMetrics in the Constructor to get the value of the factor and then calculate SP from
- * pixel values
- */
- private float mScaledDensityFactor;
- /**
- * Defines how close we want to be to the factual size of the Text-field. Lower values mean higher precision but also exponentially higher
- * computing cost (more loop runs)
- */
- private final float mThreshold = 0.5f;
- /**
- * Constructor for call without attributes --> invoke constructor with AttributeSet null
- *
- * @param context
- */
- public AutoFitText(Context context) {
- this(context, null);
- }
- public AutoFitText(Context context, AttributeSet attrs) {
- super(context, attrs);
- init(context, attrs);
- }
- public AutoFitText(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- init(context, attrs);
- }
- private void init(Context context, AttributeSet attrs) {
- //TextViewPlus part https://stackoverflow.com/a/7197867/2075875
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AutoFitText);
- String customFont = a.getString(R.styleable.AutoFitText_customFont);
- setCustomFont(context, customFont);
- a.recycle();
- // AutoFitText part
- mScaledDensityFactor = context.getResources().getDisplayMetrics().scaledDensity;
- mTestView = new TextView(context);
- mTestPaint = new Paint();
- mTestPaint.set(this.getPaint());
- this.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
- @Override
- public void onGlobalLayout() {
- // make an initial call to onSizeChanged to make sure that refitText is triggered
- onSizeChanged(AutoFitText.this.getWidth(), AutoFitText.this.getHeight(), 0, 0);
- // Remove the LayoutListener immediately so we don't run into an infinite loop
- //AutoFitText.this.getViewTreeObserver().removeOnGlobalLayoutListener(this);
- removeOnGlobalLayoutListener(AutoFitText.this, this);
- }
- });
- }
- public boolean setCustomFont(Context ctx, String asset) {
- Typeface tf = null;
- try {
- tf = Typeface.createFromAsset(ctx.getAssets(), asset);
- } catch (Exception e) {
- LOG.e(TAG, "Could not get typeface: "+e.getMessage());
- return false;
- }
- setTypeface(tf);
- return true;
- }
- @SuppressLint("NewApi")
- public static void removeOnGlobalLayoutListener(View v, ViewTreeObserver.OnGlobalLayoutListener listener){
- if (Build.VERSION.SDK_INT < 16) {
- v.getViewTreeObserver().removeGlobalOnLayoutListener(listener);
- } else {
- v.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
- }
- }
- /**
- * Main method of this widget. Resizes the font so the specified text fits in the text box assuming the text box has the specified width. This is
- * done via a dummy text view that is refit until it matches the real target width and height up to a certain threshold factor
- *
- * @param targetFieldWidth The width that the TextView currently has and wants filled
- * @param targetFieldHeight The width that the TextView currently has and wants filled
- */
- private void refitText(String text, int targetFieldWidth, int targetFieldHeight) {
- // Variables need to be visible outside the loops for later use. Remember size is in pixels
- float lowerTextSize = MIN_TEXT_SIZE;
- float upperTextSize = MAX_TEXT_SIZE;
- // Force the text to wrap. In principle this is not necessary since the dummy TextView
- // already does this for us but in rare cases adding this line can prevent flickering
- this.setMaxWidth(targetFieldWidth);
- // Padding should not be an issue since we never define it programmatically in this app
- // but just to to be sure we cut it off here
- targetFieldWidth = targetFieldWidth - this.getPaddingLeft() - this.getPaddingRight();
- targetFieldHeight = targetFieldHeight - this.getPaddingTop() - this.getPaddingBottom();
- // Initialize the dummy with some params (that are largely ignored anyway, but this is
- // mandatory to not get a NullPointerException)
- mTestView.setLayoutParams(new LayoutParams(targetFieldWidth, targetFieldHeight));
- // maxWidth is crucial! Otherwise the text would never line wrap but blow up the width
- mTestView.setMaxWidth(targetFieldWidth);
- if (mSingleLine) {
- // the user requested a single line. This is very easy to do since we primarily need to
- // respect the width, don't have to break, don't have to measure...
- /*************************** Converging algorithm 1 ***********************************/
- for (float testSize; (upperTextSize - lowerTextSize) > mThreshold;) {
- // Go to the mean value...
- testSize = (upperTextSize + lowerTextSize) / 2;
- mTestView.setTextSize(TypedValue.COMPLEX_UNIT_SP, testSize / mScaledDensityFactor);
- mTestView.setText(text);
- mTestView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
- if (mTestView.getMeasuredWidth() >= targetFieldWidth) {
- upperTextSize = testSize; // Font is too big, decrease upperSize
- } else {
- lowerTextSize = testSize; // Font is too small, increase lowerSize
- }
- }
- /**************************************************************************************/
- // In rare cases with very little letters and width > height we have vertical overlap!
- mTestView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
- if (mTestView.getMeasuredHeight() > targetFieldHeight) {
- upperTextSize = lowerTextSize;
- lowerTextSize = MIN_TEXT_SIZE;
- /*************************** Converging algorithm 1.5 *****************************/
- for (float testSize; (upperTextSize - lowerTextSize) > mThreshold;) {
- // Go to the mean value...
- testSize = (upperTextSize + lowerTextSize) / 2;
- mTestView.setTextSize(TypedValue.COMPLEX_UNIT_SP, testSize / mScaledDensityFactor);
- mTestView.setText(text);
- mTestView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
- if (mTestView.getMeasuredHeight() >= targetFieldHeight) {
- upperTextSize = testSize; // Font is too big, decrease upperSize
- } else {
- lowerTextSize = testSize; // Font is too small, increase lowerSize
- }
- }
- /**********************************************************************************/
- }
- } else {
- /*********************** Converging algorithm 2 ***************************************/
- // Upper and lower size converge over time. As soon as they're close enough the loop
- // stops
- // TODO probe the algorithm for cost (ATM possibly O(n^2)) and optimize if possible
- for (float testSize; (upperTextSize - lowerTextSize) > mThreshold;) {
- // Go to the mean value...
- testSize = (upperTextSize + lowerTextSize) / 2;
- // ... inflate the dummy TextView by setting a scaled textSize and the text...
- mTestView.setTextSize(TypedValue.COMPLEX_UNIT_SP, testSize / mScaledDensityFactor);
- mTestView.setText(text);
- // ... call measure to find the current values that the text WANTS to occupy
- mTestView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
- int tempHeight = mTestView.getMeasuredHeight();
- // int tempWidth = mTestView.getMeasuredWidth();
- // LOG.debug("Measured: " + tempWidth + "x" + tempHeight);
- // LOG.debug("TextSize: " + testSize / mScaledDensityFactor);
- // ... decide whether those values are appropriate.
- if (tempHeight >= targetFieldHeight) {
- upperTextSize = testSize; // Font is too big, decrease upperSize
- } else {
- lowerTextSize = testSize; // Font is too small, increase lowerSize
- }
- }
- /**************************************************************************************/
- // It is possible that a single word is wider than the box. The Android system would
- // wrap this for us. But if you want to decide fo yourself where exactly to break or to
- // add a hyphen or something than you're going to want to implement something like this:
- mTestPaint.setTextSize(lowerTextSize);
- List<String> words = new ArrayList<String>();
- for (String s : text.split(" ")) {
- Log.i("tag", "Word: " + s);
- words.add(s);
- }
- for (String word : words) {
- if (mTestPaint.measureText(word) >= targetFieldWidth) {
- List<String> pieces = new ArrayList<String>();
- // pieces = breakWord(word, mTestPaint.measureText(word), targetFieldWidth);
- // Add code to handle the pieces here...
- }
- }
- }
- /**
- * We are now at most the value of threshold away from the actual size. To rather undershoot than overshoot use the lower value. To match
- * different screens convert to SP first. See {@link http://developer.android.com/guide/topics/resources/more-resources.html#Dimension} for
- * more details
- */
- this.setTextSize(TypedValue.COMPLEX_UNIT_SP, lowerTextSize / mScaledDensityFactor);
- return;
- }
- /**
- * This method receives a call upon a change in text content of the TextView. Unfortunately it is also called - among others - upon text size
- * change which means that we MUST NEVER CALL {@link #refitText(String)} from this method! Doing so would result in an endless loop that would
- * ultimately result in a stack overflow and termination of the application
- *
- * So for the time being this method does absolutely nothing. If you want to notify the view of a changed text call {@link #setText(CharSequence)}
- */
- @Override
- protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
- // Super implementation is also intentionally empty so for now we do absolutely nothing here
- super.onTextChanged(text, start, lengthBefore, lengthAfter);
- }
- @Override
- protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
- if (width != oldWidth && height != oldHeight) {
- refitText(this.getText().toString(), width, height);
- }
- }
- /**
- * This method is guaranteed to be called by {@link TextView#setText(CharSequence)} immediately. Therefore we can safely add our modifications
- * here and then have the parent class resume its work. So if text has changed you should always call {@link TextView#setText(CharSequence)} or
- * {@link TextView#setText(CharSequence, BufferType)} if you know whether the {@link BufferType} is normal, editable or spannable. Note: the
- * method will default to {@link BufferType#NORMAL} if you don't pass an argument.
- */
- @Override
- public void setText(CharSequence text, BufferType type) {
- int targetFieldWidth = this.getWidth();
- int targetFieldHeight = this.getHeight();
- if (targetFieldWidth <= 0 || targetFieldHeight <= 0 || text.equals("")) {
- // Log.v("tag", "Some values are empty, AutoFitText was not able to construct properly");
- } else {
- refitText(text.toString(), targetFieldWidth, targetFieldHeight);
- }
- super.setText(text, type);
- }
- /**
- * TODO add sensibility for {@link #setMaxLines(int)} invocations
- */
- @Override
- public void setMaxLines(int maxLines) {
- // TODO Implement support for this. This could be relatively easy. The idea would probably
- // be to manipulate the targetHeight in the refitText-method and then have the algorithm do
- // its job business as usual. Nonetheless, remember the height will have to be lowered
- // dynamically as the font size shrinks so it won't be a walk in the park still
- if (maxLines == 1) {
- this.setSingleLine(true);
- } else {
- throw new UnsupportedOperationException("MaxLines != 1 are not implemented in AutoFitText yet, use TextView instead");
- }
- }
- @Override
- public void setSingleLine(boolean singleLine) {
- // save the requested value in an instance variable to be able to decide later
- mSingleLine = singleLine;
- super.setSingleLine(singleLine);
- }
- }
- TextWatcher changeText = new TextWatcher() {
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- tv3.setText(et.getText().toString());
- tv3.post(new Runnable() {
- @Override
- public void run() {
- while(tv3.getLineCount() >= 3){
- tv3.setTextSize((tv3.getTextSize())-1);
- }
- }
- });
- }
- @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
- @Override public void afterTextChanged(Editable s) { }
- };
- public MyTextView extends TextView{
- public void resize(String text, float textViewWidth, float textViewHeight) {
- Paint p = new Paint();
- Rect bounds = new Rect();
- p.setTextSize(1);
- p.getTextBounds(text, 0, text.length(), bounds);
- float widthDifference = (textViewWidth)/bounds.width();
- float heightDifference = (textViewHeight);
- textSize = Math.min(widthDifference, heightDifference);
- setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
- }
- public void setTextCompat(final CharSequence text) {
- setTextCompat(text, BufferType.NORMAL);
- }
- public void setTextCompat(final CharSequence text, BufferType type) {
- // Quick fix for Android Honeycomb and Ice Cream Sandwich which sets the text only on the first call
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1 &&
- Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
- super.setText(DOUBLE_BYTE_WORDJOINER + text + DOUBLE_BYTE_WORDJOINER, type);
- } else {
- super.setText(text, type);
- }
- }
- @Override
- public CharSequence getText() {
- String originalText = super.getText().toString();
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1 &&
- Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
- // We try to remove the word joiners we added using compat method - if none found - this will do nothing.
- return originalText.replaceAll(DOUBLE_BYTE_WORDJOINER, "");
- } else {
- return originalText;
- }
- }
- public void autoResizeTextView(final TextView tvContent, final View parent,
- final float originalSize, final int maxLine) {
- tvContent.setVisibility(View.INVISIBLE);
- tvContent.getViewTreeObserver()
- .addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
- private float mOriginalSize = originalSize;
- private float mParentWidth = 0f;
- @Override
- public void onGlobalLayout() {
- // get parent width just only one time.
- if (mParentWidth == 0f) {
- mParentWidth = parent.getMeasuredWidth();
- }
- if (tvContent.getMeasuredWidth() == mParentWidth
- && tvContent.getLineCount() > maxLine) {
- mOriginalSize -= 0.5f;
- tvContent.setTextSize(mOriginalSize);
- } else {
- tvContent.setVisibility(View.VISIBLE);
- tvContent.getViewTreeObserver()
- .removeOnGlobalLayoutListener(this);
- }
- }
- });
- }
- textview.setLayoutParams(new LayoutParams(LinearLayout.MATCH_PARENT,LinearLayout.WRAP_CONTENT));
- int GeneralApproxWidthOfContainer = 400;
- int GeneralApproxHeightOfContainer = 600;
- textview.setMaxWidth(400);
- textview.setMaxHeight(600);`
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:autoSizeTextType="uniform"
- app:autoSizeMinTextSize="12sp"
- app:autoSizeMaxTextSize="100sp"
- app:autoSizeStepGranularity="2sp"
- />
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement