truongngoclinh

AutoFitText

Oct 18th, 2019
139
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 26.42 KB | None | 0 0
  1. /**
  2.  * A {@link TextView} that re-sizes its text to be no larger than the width of the view.
  3.  *
  4.  * @attr ref R.styleable.AutofitTextView_sizeToFit
  5.  * @attr ref R.styleable.AutofitTextView_minTextSize
  6.  * @attr ref R.styleable.AutofitTextView_precision
  7.  */
  8. public class AutofitTextView extends AppCompatTextView implements AutofitHelper.OnTextSizeChangeListener {
  9.  
  10.     private AutofitHelper mHelper;
  11.  
  12.     public AutofitTextView(Context context) {
  13.         super(context);
  14.         init(context, null, 0);
  15.     }
  16.  
  17.     public AutofitTextView(Context context, AttributeSet attrs) {
  18.         super(context, attrs);
  19.         init(context, attrs, 0);
  20.     }
  21.  
  22.     public AutofitTextView(Context context, AttributeSet attrs, int defStyle) {
  23.         super(context, attrs, defStyle);
  24.         init(context, attrs, defStyle);
  25.     }
  26.  
  27.     private void init(Context context, AttributeSet attrs, int defStyle) {
  28.         mHelper = AutofitHelper.create(this, attrs, defStyle)
  29.                 .addOnTextSizeChangeListener(this);
  30.     }
  31.  
  32.     // Getters and Setters
  33.  
  34.     /**
  35.      * {@inheritDoc}
  36.      */
  37.     @Override
  38.     public void setTextSize(int unit, float size) {
  39.         super.setTextSize(unit, size);
  40.         if (mHelper != null) {
  41.             mHelper.setTextSize(unit, size);
  42.         }
  43.     }
  44.  
  45.     /**
  46.      * {@inheritDoc}
  47.      */
  48.     @Override
  49.     public void setLines(int lines) {
  50.         super.setLines(lines);
  51.         if (mHelper != null) {
  52.             mHelper.setMaxLines(lines);
  53.         }
  54.     }
  55.  
  56.     /**
  57.      * {@inheritDoc}
  58.      */
  59.     @Override
  60.     public void setMaxLines(int maxLines) {
  61.         super.setMaxLines(maxLines);
  62.         if (mHelper != null) {
  63.             mHelper.setMaxLines(maxLines);
  64.         }
  65.     }
  66.  
  67.     /**
  68.      * Returns the {@link AutofitHelper} for this View.
  69.      */
  70.     public AutofitHelper getAutofitHelper() {
  71.         return mHelper;
  72.     }
  73.  
  74.     /**
  75.      * Returns whether or not the text will be automatically re-sized to fit its constraints.
  76.      */
  77.     public boolean isSizeToFit() {
  78.         return mHelper.isEnabled();
  79.     }
  80.  
  81.     /**
  82.      * Sets the property of this field (sizeToFit), to automatically resize the text to fit its
  83.      * constraints.
  84.      */
  85.     public void setSizeToFit() {
  86.         setSizeToFit(true);
  87.     }
  88.  
  89.     /**
  90.      * If true, the text will automatically be re-sized to fit its constraints; if false, it will
  91.      * act like a normal TextView.
  92.      *
  93.      * @param sizeToFit
  94.      */
  95.     public void setSizeToFit(boolean sizeToFit) {
  96.         mHelper.setEnabled(sizeToFit);
  97.     }
  98.  
  99.     /**
  100.      * Returns the maximum size (in pixels) of the text in this View.
  101.      */
  102.     public float getMaxTextSize() {
  103.         return mHelper.getMaxTextSize();
  104.     }
  105.  
  106.     /**
  107.      * Set the maximum text size to the given value, interpreted as "scaled pixel" units. This size
  108.      * is adjusted based on the current density and user font size preference.
  109.      *
  110.      * @param size The scaled pixel size.
  111.      *
  112.      * @attr ref android.R.styleable#TextView_textSize
  113.      */
  114.     public void setMaxTextSize(float size) {
  115.         mHelper.setMaxTextSize(size);
  116.     }
  117.  
  118.     /**
  119.      * Set the maximum text size to a given unit and value. See TypedValue for the possible
  120.      * dimension units.
  121.      *
  122.      * @param unit The desired dimension unit.
  123.      * @param size The desired size in the given units.
  124.      *
  125.      * @attr ref android.R.styleable#TextView_textSize
  126.      */
  127.     public void setMaxTextSize(int unit, float size) {
  128.         mHelper.setMaxTextSize(unit, size);
  129.     }
  130.  
  131.     /**
  132.      * Returns the minimum size (in pixels) of the text in this View.
  133.      */
  134.     public float getMinTextSize() {
  135.         return mHelper.getMinTextSize();
  136.     }
  137.  
  138.     /**
  139.      * Set the minimum text size to the given value, interpreted as "scaled pixel" units. This size
  140.      * is adjusted based on the current density and user font size preference.
  141.      *
  142.      * @param minSize The scaled pixel size.
  143.      *
  144.      * @attr ref me.grantland.R.styleable#AutofitTextView_minTextSize
  145.      */
  146.     public void setMinTextSize(int minSize) {
  147.         mHelper.setMinTextSize(TypedValue.COMPLEX_UNIT_SP, minSize);
  148.     }
  149.  
  150.     /**
  151.      * Set the minimum text size to a given unit and value. See TypedValue for the possible
  152.      * dimension units.
  153.      *
  154.      * @param unit The desired dimension unit.
  155.      * @param minSize The desired size in the given units.
  156.      *
  157.      * @attr ref me.grantland.R.styleable#AutofitTextView_minTextSize
  158.      */
  159.     public void setMinTextSize(int unit, float minSize) {
  160.         mHelper.setMinTextSize(unit, minSize);
  161.     }
  162.  
  163.     /**
  164.      * Returns the amount of precision used to calculate the correct text size to fit within its
  165.      * bounds.
  166.      */
  167.     public float getPrecision() {
  168.         return mHelper.getPrecision();
  169.     }
  170.  
  171.     /**
  172.      * Set the amount of precision used to calculate the correct text size to fit within its
  173.      * bounds. Lower precision is more precise and takes more time.
  174.      *
  175.      * @param precision The amount of precision.
  176.      */
  177.     public void setPrecision(float precision) {
  178.         mHelper.setPrecision(precision);
  179.     }
  180.  
  181.     @Override
  182.     public void onTextSizeChange(float textSize, float oldTextSize) {
  183.         // do nothing
  184.     }
  185. }
  186.  
  187.  
  188. /**
  189.  * A {@link ViewGroup} that re-sizes the text of it's children to be no larger than the width of the
  190.  * view.
  191.  *
  192.  * @attr ref R.styleable.AutofitTextView_sizeToFit
  193.  * @attr ref R.styleable.AutofitTextView_minTextSize
  194.  * @attr ref R.styleable.AutofitTextView_precision
  195.  */
  196. public class AutofitLayout extends FrameLayout {
  197.  
  198.     private boolean mEnabled;
  199.     private float mMinTextSize;
  200.     private float mPrecision;
  201.     private WeakHashMap<View, AutofitHelper> mHelpers = new WeakHashMap<View, AutofitHelper>();
  202.  
  203.     public AutofitLayout(Context context) {
  204.         super(context);
  205.         init(context, null, 0);
  206.     }
  207.  
  208.     public AutofitLayout(Context context, AttributeSet attrs) {
  209.         super(context, attrs);
  210.         init(context, attrs, 0);
  211.     }
  212.  
  213.     public AutofitLayout(Context context, AttributeSet attrs, int defStyle) {
  214.         super(context, attrs, defStyle);
  215.         init(context, attrs, defStyle);
  216.     }
  217.  
  218.     private void init(Context context, AttributeSet attrs, int defStyle) {
  219.         boolean sizeToFit = true;
  220.         int minTextSize = -1;
  221.         float precision = -1;
  222.  
  223.         if (attrs != null) {
  224.             TypedArray ta = context.obtainStyledAttributes(
  225.                     attrs,
  226.                     R.styleable.AutofitTextView,
  227.                     defStyle,
  228.                     0);
  229.             sizeToFit = ta.getBoolean(R.styleable.AutofitTextView_sizeToFit, sizeToFit);
  230.             minTextSize = ta.getDimensionPixelSize(R.styleable.AutofitTextView_minTextSize,
  231.                     minTextSize);
  232.             precision = ta.getFloat(R.styleable.AutofitTextView_precision, precision);
  233.             ta.recycle();
  234.         }
  235.  
  236.         mEnabled = sizeToFit;
  237.         mMinTextSize = minTextSize;
  238.         mPrecision = precision;
  239.     }
  240.  
  241.     @Override
  242.     public void addView(View child, int index, ViewGroup.LayoutParams params) {
  243.         super.addView(child, index, params);
  244.         TextView textView = (TextView) child;
  245.         AutofitHelper helper = AutofitHelper.create(textView)
  246.                 .setEnabled(mEnabled);
  247.         if (mPrecision > 0) {
  248.             helper.setPrecision(mPrecision);
  249.         }
  250.         if (mMinTextSize > 0) {
  251.             helper.setMinTextSize(TypedValue.COMPLEX_UNIT_PX, mMinTextSize);
  252.         }
  253.         mHelpers.put(textView, helper);
  254.     }
  255.  
  256.     /**
  257.      * Returns the {@link AutofitHelper} for this child View.
  258.      */
  259.     public AutofitHelper getAutofitHelper(TextView textView) {
  260.         return mHelpers.get(textView);
  261.     }
  262.  
  263.     /**
  264.      * Returns the {@link AutofitHelper} for this child View.
  265.      */
  266.     public AutofitHelper getAutofitHelper(int index) {
  267.         return mHelpers.get(getChildAt(index));
  268.     }
  269. }
  270.  
  271.  
  272. /**
  273.  * A helper class to enable automatically resizing {@link TextView}`s {@code textSize} to fit
  274.  * within its bounds.
  275.  *
  276.  * @attr ref R.styleable.AutofitTextView_sizeToFit
  277.  * @attr ref R.styleable.AutofitTextView_minTextSize
  278.  * @attr ref R.styleable.AutofitTextView_precision
  279.  */
  280. public class AutofitHelper {
  281.     private static final int TAG_KEY_ON_LAYOUT_CHANGED_LISTENER = 0x31;
  282.     private static final String TAG = "AutoFitTextHelper";
  283.     private static final boolean SPEW = false;
  284.  
  285.     // Minimum size of the text in pixels
  286.     private static final int DEFAULT_MIN_TEXT_SIZE = 8; //sp
  287.     // How precise we want to be when reaching the target textWidth size
  288.     private static final float DEFAULT_PRECISION = 0.5f;
  289.  
  290.     /**
  291.      * Creates a new instance of {@code AutofitHelper} that wraps a {@link TextView} and enables
  292.      * automatically sizing the text to fit.
  293.      */
  294.     public static AutofitHelper create(TextView view) {
  295.         return create(view, null, 0);
  296.     }
  297.  
  298.     /**
  299.      * Creates a new instance of {@code AutofitHelper} that wraps a {@link TextView} and enables
  300.      * automatically sizing the text to fit.
  301.      */
  302.     public static AutofitHelper create(TextView view, AttributeSet attrs) {
  303.         return create(view, attrs, 0);
  304.     }
  305.  
  306.     /**
  307.      * Creates a new instance of {@code AutofitHelper} that wraps a {@link TextView} and enables
  308.      * automatically sizing the text to fit.
  309.      */
  310.     public static AutofitHelper create(TextView view, AttributeSet attrs, int defStyle) {
  311.         AutofitHelper helper = new AutofitHelper(view);
  312.         boolean sizeToFit = true;
  313.         if (attrs != null) {
  314.             Context context = view.getContext();
  315.             int minTextSize = (int) helper.getMinTextSize();
  316.             float precision = helper.getPrecision();
  317.  
  318.             TypedArray ta = context.obtainStyledAttributes(
  319.                     attrs,
  320.                     R.styleable.AutofitTextView,
  321.                     defStyle,
  322.                     0);
  323.             sizeToFit = ta.getBoolean(R.styleable.AutofitTextView_sizeToFit, sizeToFit);
  324.             minTextSize = ta.getDimensionPixelSize(R.styleable.AutofitTextView_minTextSize,
  325.                     minTextSize);
  326.             precision = ta.getFloat(R.styleable.AutofitTextView_precision, precision);
  327.             ta.recycle();
  328.  
  329.             helper.setMinTextSize(TypedValue.COMPLEX_UNIT_PX, minTextSize)
  330.                 .setPrecision(precision);
  331.         }
  332.         if (Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB) {
  333.             helper.setEnabled(sizeToFit);
  334.         }
  335.  
  336.         return helper;
  337.     }
  338.  
  339.     /**
  340.      * Re-sizes the textSize of the TextView so that the text fits within the bounds of the View.
  341.      */
  342.     private static void autofit(TextView view, TextPaint paint, float minTextSize, float maxTextSize,
  343.                                 int maxLines, float precision) {
  344.         if (maxLines <= 0 || maxLines == Integer.MAX_VALUE) {
  345.             // Don't auto-size since there's no limit on lines.
  346.             return;
  347.         }
  348.  
  349.         int targetWidth = view.getWidth() - view.getCompoundPaddingLeft() - view.getCompoundPaddingRight();
  350.         if (targetWidth <= 0) {
  351.             return;
  352.         }
  353.  
  354.         CharSequence text = view.getText();
  355.         TransformationMethod method = view.getTransformationMethod();
  356.         if (method != null) {
  357.             text = method.getTransformation(text, view);
  358.         }
  359.  
  360.         Context context = view.getContext();
  361.         Resources r = Resources.getSystem();
  362.         DisplayMetrics displayMetrics;
  363.  
  364.         float size = maxTextSize;
  365.         float high = size;
  366.         float low = 0;
  367.  
  368.         if (context != null) {
  369.             r = context.getResources();
  370.         }
  371.         displayMetrics = r.getDisplayMetrics();
  372.  
  373.         paint.set(view.getPaint());
  374.         paint.setTextSize(size);
  375.  
  376.         if ((maxLines == 1 && paint.measureText(text, 0, text.length()) > targetWidth)
  377.                 || getLineCount(text, paint, size, targetWidth, displayMetrics) > maxLines) {
  378.             size = getAutofitTextSize(text, paint, targetWidth, maxLines, low, high, precision,
  379.                     displayMetrics);
  380.         }
  381.  
  382.         if (size < minTextSize) {
  383.             size = minTextSize;
  384.         }
  385.  
  386.         view.setTextSize(TypedValue.COMPLEX_UNIT_PX, size);
  387.     }
  388.  
  389.     /**
  390.      * Recursive binary search to find the best size for the text.
  391.      */
  392.     private static float getAutofitTextSize(CharSequence text, TextPaint paint,
  393.                                             float targetWidth, int maxLines, float low, float high, float precision,
  394.                                             DisplayMetrics displayMetrics) {
  395.         float mid = (low + high) / 2.0f;
  396.         int lineCount = 1;
  397.         StaticLayout layout = null;
  398.  
  399.         paint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, mid,
  400.                 displayMetrics));
  401.  
  402.         if (maxLines != 1) {
  403.             layout = new StaticLayout(text, paint, (int)targetWidth, Layout.Alignment.ALIGN_NORMAL,
  404.                     1.0f, 0.0f, true);
  405.             lineCount = layout.getLineCount();
  406.         }
  407.  
  408.         if (SPEW) Log.d(TAG, "low=" + low + " high=" + high + " mid=" + mid +
  409.                 " target=" + targetWidth + " maxLines=" + maxLines + " lineCount=" + lineCount);
  410.  
  411.         if (lineCount > maxLines) {
  412.             // For the case that `text` has more newline characters than `maxLines`.
  413.             if ((high - low) < precision) {
  414.                 return low;
  415.             }
  416.             return getAutofitTextSize(text, paint, targetWidth, maxLines, low, mid, precision,
  417.                     displayMetrics);
  418.         }
  419.         else if (lineCount < maxLines) {
  420.             return getAutofitTextSize(text, paint, targetWidth, maxLines, mid, high, precision,
  421.                     displayMetrics);
  422.         }
  423.         else {
  424.             float maxLineWidth = 0;
  425.             if (maxLines == 1) {
  426.                 maxLineWidth = paint.measureText(text, 0, text.length());
  427.             } else {
  428.                 for (int i = 0; i < lineCount; i++) {
  429.                     if (layout.getLineWidth(i) > maxLineWidth) {
  430.                         maxLineWidth = layout.getLineWidth(i);
  431.                     }
  432.                 }
  433.             }
  434.  
  435.             if ((high - low) < precision) {
  436.                 return low;
  437.             } else if (maxLineWidth > targetWidth) {
  438.                 return getAutofitTextSize(text, paint, targetWidth, maxLines, low, mid, precision,
  439.                         displayMetrics);
  440.             } else if (maxLineWidth < targetWidth) {
  441.                 return getAutofitTextSize(text, paint, targetWidth, maxLines, mid, high, precision,
  442.                         displayMetrics);
  443.             } else {
  444.                 return mid;
  445.             }
  446.         }
  447.     }
  448.  
  449.     private static int getLineCount(CharSequence text, TextPaint paint, float size, float width,
  450.                                     DisplayMetrics displayMetrics) {
  451.         paint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, size,
  452.                 displayMetrics));
  453.         StaticLayout layout = new StaticLayout(text, paint, (int)width,
  454.                 Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, true);
  455.         return layout.getLineCount();
  456.     }
  457.  
  458.     private static int getMaxLines(TextView view) {
  459.         int maxLines = -1; // No limit (Integer.MAX_VALUE also means no limit)
  460.  
  461.         TransformationMethod method = view.getTransformationMethod();
  462.         if (method != null && method instanceof SingleLineTransformationMethod) {
  463.             maxLines = 1;
  464.         }
  465.         else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
  466.             // setMaxLines() and getMaxLines() are only available on android-16+
  467.             maxLines = view.getMaxLines();
  468.         }
  469.  
  470.         return maxLines;
  471.     }
  472.  
  473.     // Attributes
  474.     private TextView mTextView;
  475.     private TextPaint mPaint;
  476.     /**
  477.      * Original textSize of the TextView.
  478.      */
  479.     private float mTextSize;
  480.  
  481.     private int mMaxLines;
  482.     private float mMinTextSize;
  483.     private float mMaxTextSize;
  484.     private float mPrecision;
  485.  
  486.     private boolean mEnabled;
  487.     private boolean mIsAutofitting;
  488.  
  489.     private ArrayList<OnTextSizeChangeListener> mListeners;
  490.  
  491.     private TextWatcher mTextWatcher = new AutofitTextWatcher();
  492.  
  493.     private AutofitHelper(TextView view) {
  494.         final Context context = view.getContext();
  495.         float scaledDensity = context.getResources().getDisplayMetrics().scaledDensity;
  496.  
  497.         mTextView = view;
  498.         mTextView.setSingleLine(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB);
  499.         mPaint = new TextPaint();
  500.         setRawTextSize(view.getTextSize());
  501.  
  502.         mMaxLines = getMaxLines(view);
  503.         mMinTextSize = scaledDensity * DEFAULT_MIN_TEXT_SIZE;
  504.         mMaxTextSize = mTextSize;
  505.         mPrecision = DEFAULT_PRECISION;
  506.     }
  507.  
  508.     /**
  509.      * Adds an {@link OnTextSizeChangeListener} to the list of those whose methods are called
  510.      * whenever the {@link TextView}'s {@code textSize} changes.
  511.      */
  512.     public AutofitHelper addOnTextSizeChangeListener(OnTextSizeChangeListener listener) {
  513.         if (mListeners == null) {
  514.             mListeners = new ArrayList<OnTextSizeChangeListener>();
  515.         }
  516.         mListeners.add(listener);
  517.         return this;
  518.     }
  519.  
  520.     /**
  521.      * Removes the specified {@link OnTextSizeChangeListener} from the list of those whose methods
  522.      * are called whenever the {@link TextView}'s {@code textSize} changes.
  523.      */
  524.     public AutofitHelper removeOnTextSizeChangeListener(OnTextSizeChangeListener listener) {
  525.         if (mListeners != null) {
  526.             mListeners.remove(listener);
  527.         }
  528.         return this;
  529.     }
  530.  
  531.     /**
  532.      * Returns the amount of precision used to calculate the correct text size to fit within its
  533.      * bounds.
  534.      */
  535.     public float getPrecision() {
  536.         return mPrecision;
  537.     }
  538.  
  539.     /**
  540.      * Set the amount of precision used to calculate the correct text size to fit within its
  541.      * bounds. Lower precision is more precise and takes more time.
  542.      *
  543.      * @param precision The amount of precision.
  544.      */
  545.     public AutofitHelper setPrecision(float precision) {
  546.         if (mPrecision != precision) {
  547.             mPrecision = precision;
  548.  
  549.             autofit();
  550.         }
  551.         return this;
  552.     }
  553.  
  554.     /**
  555.      * Returns the minimum size (in pixels) of the text.
  556.      */
  557.     public float getMinTextSize() {
  558.         return mMinTextSize;
  559.     }
  560.  
  561.     /**
  562.      * Set the minimum text size to the given value, interpreted as "scaled pixel" units. This size
  563.      * is adjusted based on the current density and user font size preference.
  564.      *
  565.      * @param size The scaled pixel size.
  566.      *
  567.      * @attr ref me.grantland.R.styleable#AutofitTextView_minTextSize
  568.      */
  569.     public AutofitHelper setMinTextSize(float size) {
  570.         return setMinTextSize(TypedValue.COMPLEX_UNIT_SP, size);
  571.     }
  572.  
  573.     /**
  574.      * Set the minimum text size to a given unit and value. See TypedValue for the possible
  575.      * dimension units.
  576.      *
  577.      * @param unit The desired dimension unit.
  578.      * @param size The desired size in the given units.
  579.      *
  580.      * @attr ref me.grantland.R.styleable#AutofitTextView_minTextSize
  581.      */
  582.     public AutofitHelper setMinTextSize(int unit, float size) {
  583.         Context context = mTextView.getContext();
  584.         Resources r = Resources.getSystem();
  585.  
  586.         if (context != null) {
  587.             r = context.getResources();
  588.         }
  589.  
  590.         setRawMinTextSize(TypedValue.applyDimension(unit, size, r.getDisplayMetrics()));
  591.         return this;
  592.     }
  593.  
  594.     private void setRawMinTextSize(float size) {
  595.         if (size != mMinTextSize) {
  596.             mMinTextSize = size;
  597.  
  598.             autofit();
  599.         }
  600.     }
  601.  
  602.     /**
  603.      * Returns the maximum size (in pixels) of the text.
  604.      */
  605.     public float getMaxTextSize() {
  606.         return mMaxTextSize;
  607.     }
  608.  
  609.     /**
  610.      * Set the maximum text size to the given value, interpreted as "scaled pixel" units. This size
  611.      * is adjusted based on the current density and user font size preference.
  612.      *
  613.      * @param size The scaled pixel size.
  614.      *
  615.      * @attr ref android.R.styleable#TextView_textSize
  616.      */
  617.     public AutofitHelper setMaxTextSize(float size) {
  618.         return setMaxTextSize(TypedValue.COMPLEX_UNIT_SP, size);
  619.     }
  620.  
  621.     /**
  622.      * Set the maximum text size to a given unit and value. See TypedValue for the possible
  623.      * dimension units.
  624.      *
  625.      * @param unit The desired dimension unit.
  626.      * @param size The desired size in the given units.
  627.      *
  628.      * @attr ref android.R.styleable#TextView_textSize
  629.      */
  630.     public AutofitHelper setMaxTextSize(int unit, float size) {
  631.         Context context = mTextView.getContext();
  632.         Resources r = Resources.getSystem();
  633.  
  634.         if (context != null) {
  635.             r = context.getResources();
  636.         }
  637.  
  638.         setRawMaxTextSize(TypedValue.applyDimension(unit, size, r.getDisplayMetrics()));
  639.         return this;
  640.     }
  641.  
  642.     private void setRawMaxTextSize(float size) {
  643.         if (size != mMaxTextSize) {
  644.             mMaxTextSize = size;
  645.  
  646.             autofit();
  647.         }
  648.     }
  649.  
  650.     /**
  651.      * @see TextView#getMaxLines()
  652.      */
  653.     public int getMaxLines() {
  654.         return mMaxLines;
  655.     }
  656.  
  657.     /**
  658.      * @see TextView#setMaxLines(int)
  659.      */
  660.     public AutofitHelper setMaxLines(int lines) {
  661.         if (mMaxLines != lines) {
  662.             mMaxLines = lines;
  663.  
  664.             autofit();
  665.         }
  666.         return this;
  667.     }
  668.  
  669.     /**
  670.      * Returns whether or not automatically resizing text is enabled.
  671.      */
  672.     public boolean isEnabled() {
  673.         return mEnabled;
  674.     }
  675.  
  676.     /**
  677.      * Set the enabled state of automatically resizing text.
  678.      */
  679.     @TargetApi(11)
  680.     public AutofitHelper setEnabled(boolean enabled) {
  681.         if (mEnabled != enabled) {
  682.             mEnabled = enabled;
  683.  
  684.             if (enabled) {
  685.                 mTextView.addTextChangedListener(mTextWatcher);
  686.                 View.OnLayoutChangeListener onLayoutChangeListener = new View.OnLayoutChangeListener() {
  687.                     @Override
  688.                     public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
  689.                                                int oldTop, int oldRight, int oldBottom) {
  690.                         autofit();
  691.                     }
  692.                 };
  693.                 mTextView.addOnLayoutChangeListener(onLayoutChangeListener);
  694.                 mTextView.setTag(mTextView.getId(), onLayoutChangeListener);
  695.  
  696.                 autofit();
  697.             } else {
  698.                 mTextView.removeTextChangedListener(mTextWatcher);
  699.                 Object onLayoutChangeListener = mTextView.getTag(mTextView.getId());
  700.                 if (onLayoutChangeListener instanceof View.OnLayoutChangeListener) {
  701.                     mTextView.removeOnLayoutChangeListener((View.OnLayoutChangeListener) onLayoutChangeListener);
  702.                 }
  703.  
  704.                 mTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize);
  705.             }
  706.         }
  707.         return this;
  708.     }
  709.  
  710.     /**
  711.      * Returns the original text size of the View.
  712.      *
  713.      * @see TextView#getTextSize()
  714.      */
  715.     public float getTextSize() {
  716.         return mTextSize;
  717.     }
  718.  
  719.     /**
  720.      * Set the original text size of the View.
  721.      *
  722.      * @see TextView#setTextSize(float)
  723.      */
  724.     public void setTextSize(float size) {
  725.         setTextSize(TypedValue.COMPLEX_UNIT_SP, size);
  726.     }
  727.  
  728.     /**
  729.      * Set the original text size of the View.
  730.      *
  731.      * @see TextView#setTextSize(int, float)
  732.      */
  733.     public void setTextSize(int unit, float size) {
  734.         if (mIsAutofitting) {
  735.             // We don't want to update the TextView's actual textSize while we're autofitting
  736.             // since it'd get set to the autofitTextSize
  737.             return;
  738.         }
  739.         Context context = mTextView.getContext();
  740.         Resources r = Resources.getSystem();
  741.  
  742.         if (context != null) {
  743.             r = context.getResources();
  744.         }
  745.  
  746.         setRawTextSize(TypedValue.applyDimension(unit, size, r.getDisplayMetrics()));
  747.     }
  748.  
  749.     private void setRawTextSize(float size) {
  750.         if (mTextSize != size) {
  751.             mTextSize = size;
  752.         }
  753.     }
  754.  
  755.     private void autofit() {
  756.         float oldTextSize = mTextView.getTextSize();
  757.         float textSize;
  758.  
  759.         mIsAutofitting = true;
  760.         autofit(mTextView, mPaint, mMinTextSize, mMaxTextSize, mMaxLines, mPrecision);
  761.         mIsAutofitting = false;
  762.  
  763.         textSize = mTextView.getTextSize();
  764.         if (textSize != oldTextSize) {
  765.             sendTextSizeChange(textSize, oldTextSize);
  766.         }
  767.     }
  768.  
  769.     private void sendTextSizeChange(float textSize, float oldTextSize) {
  770.         if (mListeners == null) {
  771.             return;
  772.         }
  773.  
  774.         for (OnTextSizeChangeListener listener : mListeners) {
  775.             listener.onTextSizeChange(textSize, oldTextSize);
  776.         }
  777.     }
  778.  
  779.     private class AutofitTextWatcher implements TextWatcher {
  780.         @Override
  781.         public void beforeTextChanged(CharSequence charSequence, int start, int count, int after) {
  782.             // do nothing
  783.         }
  784.  
  785.         @Override
  786.         public void onTextChanged(CharSequence charSequence, int start, int before, int count) {
  787.             autofit();
  788.         }
  789.  
  790.         @Override
  791.         public void afterTextChanged(Editable editable) {
  792.             // do nothing
  793.         }
  794.     }
  795.  
  796.     /**
  797.      * When an object of a type is attached to an {@code AutofitHelper}, its methods will be called
  798.      * when the {@code textSize} is changed.
  799.      */
  800.     public interface OnTextSizeChangeListener {
  801.         /**
  802.          * This method is called to notify you that the size of the text has changed to
  803.          * {@code textSize} from {@code oldTextSize}.
  804.          */
  805.         public void onTextSizeChange(float textSize, float oldTextSize);
  806.     }
  807. }
  808.  
  809.  
  810. <declare-styleable name="AutofitTextView">
  811.         <!-- Minimum size of the text. -->
  812.         <attr name="minTextSize" format="dimension" />
  813.         <!-- Amount of precision used to calculate the correct text size to fit within its
  814.         bounds. Lower precision is more precise and takes more time. -->
  815.         <attr name="precision" format="float" />
  816.         <!-- Defines whether to automatically resize text to fit to the view's bounds. -->
  817.        <attr name="sizeToFit" format="boolean" />
  818. </declare-styleable
Add Comment
Please, Sign In to add comment