From a7aae1626af83e93a0dc5b1baa10e66062d4a320 Mon Sep 17 00:00:00 2001 From: serso Date: Wed, 2 Nov 2011 01:06:56 +0400 Subject: [PATCH] auto resize text view +layout changes --- res/layout-land/main_calculator.xml | 2 +- res/layout-land/main_cellphone.xml | 2 +- res/layout-port/main_calculator.xml | 2 +- res/layout-port/main_cellphone.xml | 2 +- ...rackets_button.xml => calc_dot_button.xml} | 7 +- res/layout/calc_subtraction_button.xml | 5 +- res/layout/calc_zero_digit_button.xml | 1 - .../android/calculator/CalculatorDisplay.java | 2 - .../android/view/AutoResizeTextView.java | 427 +++++++++--------- 9 files changed, 212 insertions(+), 238 deletions(-) rename res/layout/{calc_square_brackets_button.xml => calc_dot_button.xml} (81%) diff --git a/res/layout-land/main_calculator.xml b/res/layout-land/main_calculator.xml index 260cfa7a..2390e6d9 100644 --- a/res/layout-land/main_calculator.xml +++ b/res/layout-land/main_calculator.xml @@ -111,8 +111,8 @@ + - diff --git a/res/layout-land/main_cellphone.xml b/res/layout-land/main_cellphone.xml index 5e0837c1..52a0d639 100644 --- a/res/layout-land/main_cellphone.xml +++ b/res/layout-land/main_cellphone.xml @@ -105,8 +105,8 @@ + - diff --git a/res/layout-port/main_calculator.xml b/res/layout-port/main_calculator.xml index 1f0f0215..aa51b1d6 100644 --- a/res/layout-port/main_calculator.xml +++ b/res/layout-port/main_calculator.xml @@ -68,7 +68,7 @@ - + diff --git a/res/layout-port/main_cellphone.xml b/res/layout-port/main_cellphone.xml index 3d17e17b..2f2fd2c4 100644 --- a/res/layout-port/main_cellphone.xml +++ b/res/layout-port/main_cellphone.xml @@ -62,7 +62,7 @@ - + diff --git a/res/layout/calc_square_brackets_button.xml b/res/layout/calc_dot_button.xml similarity index 81% rename from res/layout/calc_square_brackets_button.xml rename to res/layout/calc_dot_button.xml index 1afa8205..d877a102 100644 --- a/res/layout/calc_square_brackets_button.xml +++ b/res/layout/calc_dot_button.xml @@ -8,10 +8,9 @@ \ No newline at end of file diff --git a/res/layout/calc_subtraction_button.xml b/res/layout/calc_subtraction_button.xml index 1dc83010..d5030359 100644 --- a/res/layout/calc_subtraction_button.xml +++ b/res/layout/calc_subtraction_button.xml @@ -7,9 +7,8 @@ --> \ No newline at end of file diff --git a/res/layout/calc_zero_digit_button.xml b/res/layout/calc_zero_digit_button.xml index ba0dea48..64119805 100644 --- a/res/layout/calc_zero_digit_button.xml +++ b/res/layout/calc_zero_digit_button.xml @@ -10,7 +10,6 @@ xmlns:calc="http://schemas.android.com/apk/res/org.solovyev.android.calculator" a:id="@+id/zeroDigitButton" a:text="0" - calc:textUp="." calc:textDown="000" calc:directionTextScale="0.5" style="?digitButtonStyle" diff --git a/src/main/java/org/solovyev/android/calculator/CalculatorDisplay.java b/src/main/java/org/solovyev/android/calculator/CalculatorDisplay.java index 869d173e..9ff202c7 100644 --- a/src/main/java/org/solovyev/android/calculator/CalculatorDisplay.java +++ b/src/main/java/org/solovyev/android/calculator/CalculatorDisplay.java @@ -87,8 +87,6 @@ public class CalculatorDisplay extends AutoResizeTextView { // todo serso: think where to move it (keep in mind org.solovyev.android.view.AutoResizeTextView.resetTextSize()) setAddEllipsis(false); setMinTextSize(10); - setMaxTextSize(70); - setTextSize(70); resizeText(); } diff --git a/src/main/java/org/solovyev/android/view/AutoResizeTextView.java b/src/main/java/org/solovyev/android/view/AutoResizeTextView.java index b64e1c97..a695bf63 100644 --- a/src/main/java/org/solovyev/android/view/AutoResizeTextView.java +++ b/src/main/java/org/solovyev/android/view/AutoResizeTextView.java @@ -12,7 +12,6 @@ import android.text.Layout.Alignment; import android.text.StaticLayout; import android.text.TextPaint; import android.util.AttributeSet; -import android.util.TypedValue; import android.widget.TextView; /** @@ -25,266 +24,246 @@ import android.widget.TextView; */ public class AutoResizeTextView extends TextView { - // Minimum text size for this text view - public static final float MIN_TEXT_SIZE = 20; + // Minimum text size for this text view + public static final float MIN_TEXT_SIZE = 20; - // Interface for resize notifications - public interface OnTextResizeListener { - public void onTextResize(TextView textView, float oldSize, float newSize); - } + // Interface for resize notifications + public interface OnTextResizeListener { + public void onTextResize(TextView textView, float oldSize, float newSize); + } - // Off screen canvas for text size rendering - private static final Canvas sTextResizeCanvas = new Canvas(); + // Off screen canvas for text size rendering + private static final Canvas sTextResizeCanvas = new Canvas(); - // Our ellipse string - private static final String mEllipsis = "..."; + // Our ellipse string + private static final String mEllipsis = "..."; - // Registered resize listener - private OnTextResizeListener mTextResizeListener; + // Registered resize listener + private OnTextResizeListener mTextResizeListener; - // Flag for text and/or size changes to force a resize - private boolean mNeedsResize = false; + // Flag for text and/or size changes to force a resize + private boolean mNeedsResize = false; - // Text size that is set from code. This acts as a starting point for resizing - private float mTextSize; + // Lower bounds for text size + private float minTextSize = MIN_TEXT_SIZE; - // Temporary upper bounds on the starting text size - private float mMaxTextSize = 0; + // Text view line spacing multiplier + private float spacingMult = 1.0f; - // Lower bounds for text size - private float mMinTextSize = MIN_TEXT_SIZE; + // Text view additional line spacing + private float spacingAdd = 0.0f; - // Text view line spacing multiplier - private float mSpacingMult = 1.0f; + // Add ellipsis to text that overflows at the smallest text size + private boolean addEllipsis = true; - // Text view additional line spacing - private float mSpacingAdd = 0.0f; + private float textSizeStartPoint = MIN_TEXT_SIZE; - // Add ellipsis to text that overflows at the smallest text size - private boolean mAddEllipsis = true; + // Default constructor override + public AutoResizeTextView(Context context) { + this(context, null); + } - // Default constructor override - public AutoResizeTextView(Context context) { - this(context, null); - } + // Default constructor when inflating from XML file + public AutoResizeTextView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } - // Default constructor when inflating from XML file - public AutoResizeTextView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } + // Default constructor override + public AutoResizeTextView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } - // Default constructor override - public AutoResizeTextView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - mTextSize = getTextSize(); - } + /** + * When text changes, set the force resize flag to true and resetInterpreter the text size. + */ + @Override + protected void onTextChanged(final CharSequence text, final int start, final int before, final int after) { + mNeedsResize = true; + // Since this view may be reused, it is good to resetInterpreter the text size + } - /** - * When text changes, set the force resize flag to true and resetInterpreter the text size. - */ - @Override - protected void onTextChanged(final CharSequence text, final int start, final int before, final int after) { - mNeedsResize = true; - // Since this view may be reused, it is good to resetInterpreter the text size - resetTextSize(); - } + /** + * If the text view size changed, set the force resize flag to true + */ + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + if (w != oldw || h != oldh) { + mNeedsResize = true; + } + } - /** - * If the text view size changed, set the force resize flag to true - */ - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - if (w != oldw || h != oldh) { - mNeedsResize = true; - } - } + /** + * Register listener to receive resize notifications + * + * @param listener + */ + public void setOnResizeListener(OnTextResizeListener listener) { + mTextResizeListener = listener; + } - /** - * Register listener to receive resize notifications - * @param listener - */ - public void setOnResizeListener(OnTextResizeListener listener) { - mTextResizeListener = listener; - } + /** + * Override the set text size to update our internal reference values + */ + @Override + public void setTextSize(int unit, float size) { + super.setTextSize(unit, size); + } - /** - * Override the set text size to update our internal reference values - */ - @Override - public void setTextSize(float size) { - super.setTextSize(size); - mTextSize = getTextSize(); - } + /** + * Override the set line spacing to update our internal reference values + */ + @Override + public void setLineSpacing(float add, float mult) { + super.setLineSpacing(add, mult); + spacingMult = mult; + spacingAdd = add; + } - /** - * Override the set text size to update our internal reference values - */ - @Override - public void setTextSize(int unit, float size) { - super.setTextSize(unit, size); - mTextSize = getTextSize(); - } + /** + * Set the lower text size limit and invalidate the view + * + * @param minTextSize + */ + public void setMinTextSize(float minTextSize) { + this.minTextSize = minTextSize; + requestLayout(); + invalidate(); + } - /** - * Override the set line spacing to update our internal reference values - */ - @Override - public void setLineSpacing(float add, float mult) { - super.setLineSpacing(add, mult); - mSpacingMult = mult; - mSpacingAdd = add; - } + /** + * Return lower text size limit + * + * @return + */ + public float getMinTextSize() { + return minTextSize; + } - /** - * Set the upper text size limit and invalidate the view - * @param maxTextSize - */ - public void setMaxTextSize(float maxTextSize) { - mMaxTextSize = maxTextSize; - requestLayout(); - invalidate(); - } + /** + * Set flag to add ellipsis to text that overflows at the smallest text size + * + * @param addEllipsis + */ + public void setAddEllipsis(boolean addEllipsis) { + this.addEllipsis = addEllipsis; + } - /** - * Return upper text size limit - * @return - */ - public float getMaxTextSize() { - return mMaxTextSize; - } + /** + * Return flag to add ellipsis to text that overflows at the smallest text size + * + * @return + */ + public boolean getAddEllipsis() { + return addEllipsis; + } - /** - * Set the lower text size limit and invalidate the view - * @param minTextSize - */ - public void setMinTextSize(float minTextSize) { - mMinTextSize = minTextSize; - requestLayout(); - invalidate(); - } - /** - * Return lower text size limit - * @return - */ - public float getMinTextSize() { - return mMinTextSize; - } + /** + * Resize text after measuring + */ + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + if (changed || mNeedsResize) { + resizeText(right - left, bottom - top); + } + super.onLayout(changed, left, top, right, bottom); + } - /** - * Set flag to add ellipsis to text that overflows at the smallest text size - * @param addEllipsis - */ - public void setAddEllipsis(boolean addEllipsis) { - mAddEllipsis = addEllipsis; - } + /** + * Resize the text size with default width and height + */ + public void resizeText() { + int heightLimit = getHeight() - getPaddingBottom() - getPaddingTop(); + int widthLimit = getWidth() - getPaddingLeft() - getPaddingRight(); + resizeText(widthLimit, heightLimit); + } - /** - * Return flag to add ellipsis to text that overflows at the smallest text size - * @return - */ - public boolean getAddEllipsis() { - return mAddEllipsis; - } + /** + * Resize the text size with specified width and height + * + * @param width + * @param height + */ + public void resizeText(int width, int height) { + CharSequence text = getText(); + // Do not resize if the view does not have dimensions or there is no text + if (text == null || text.length() == 0 || height <= 0 || width <= 0) { + return; + } - /** - * Reset the text to the original size - */ - public void resetTextSize() { - super.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize); - mMaxTextSize = mTextSize; - } + // Get the text view's paint object + TextPaint textPaint = getPaint(); - /** - * Resize text after measuring - */ - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - if(changed || mNeedsResize) { - resizeText(right - left, bottom - top); - } - super.onLayout(changed, left, top, right, bottom); - } + // Store the current text size + float oldTextSize = textPaint.getTextSize(); - /** - * Resize the text size with default width and height - */ - public void resizeText() { - int heightLimit = getHeight() - getPaddingBottom() - getPaddingTop(); - int widthLimit = getWidth() - getPaddingLeft() - getPaddingRight(); - resizeText(widthLimit, heightLimit); - } + // If there is a max text size set, use the lesser of that and the default text size + float newTextSize = textSizeStartPoint; - /** - * Resize the text size with specified width and height - * @param width - * @param height - */ - public void resizeText(int width, int height) { - CharSequence text = getText(); - // Do not resize if the view does not have dimensions or there is no text - if(text == null || text.length() == 0 || height <= 0 || width <= 0) { - return; - } + // Get the required text height + int newTextHeight = getTextRect(text, textPaint, width, newTextSize); - // Get the text view's paint object - TextPaint textPaint = getPaint(); + if (newTextHeight > height) { + // Until we either fit within our text view or we had reached our min text size, incrementally try smaller sizes + while (newTextHeight > height) { + if (newTextSize <= minTextSize) { + break; + } + newTextSize = Math.max(newTextSize - 1, minTextSize); + newTextHeight = getTextRect(text, textPaint, width, newTextSize); + } + } else { + while (newTextHeight < height) { + if (newTextSize <= minTextSize) { + break; + } + newTextSize = Math.max(newTextSize + 1, minTextSize); + newTextHeight = getTextRect(text, textPaint, width, newTextSize); + } + } - // Store the current text size - float oldTextSize = textPaint.getTextSize(); - // If there is a max text size set, use the lesser of that and the default text size - float targetTextSize = mMaxTextSize > 0 ? Math.min(mTextSize, mMaxTextSize) : mTextSize; + textSizeStartPoint = newTextSize; - // Get the required text height - int textHeight = getTextHeight(text, textPaint, width, targetTextSize); + // If we had reached our minimum text size and still don't fit, append an ellipsis + if (addEllipsis && newTextSize == minTextSize && newTextHeight > height) { + // Draw using a static layout + StaticLayout layout = new StaticLayout(text, textPaint, width, Alignment.ALIGN_NORMAL, spacingMult, spacingAdd, false); + layout.draw(sTextResizeCanvas); + int lastLine = layout.getLineForVertical(height) - 1; + int start = layout.getLineStart(lastLine); + int end = layout.getLineEnd(lastLine); + float lineWidth = layout.getLineWidth(lastLine); + float ellipseWidth = textPaint.measureText(mEllipsis); - // Until we either fit within our text view or we had reached our min text size, incrementally try smaller sizes - while(textHeight > height && targetTextSize > mMinTextSize) { - targetTextSize = Math.max(targetTextSize - 2, mMinTextSize); - textHeight = getTextHeight(text, textPaint, width, targetTextSize); - } + // Trim characters off until we have enough room to draw the ellipsis + while (width < lineWidth + ellipseWidth) { + lineWidth = textPaint.measureText(text.subSequence(start, --end + 1).toString()); + } + setText(text.subSequence(0, end) + mEllipsis); - // If we had reached our minimum text size and still don't fit, append an ellipsis - if(mAddEllipsis && targetTextSize == mMinTextSize && textHeight > height) { - // Draw using a static layout - StaticLayout layout = new StaticLayout(text, textPaint, width, Alignment.ALIGN_NORMAL, mSpacingMult, mSpacingAdd, false); - layout.draw(sTextResizeCanvas); - int lastLine = layout.getLineForVertical(height) - 1; - int start = layout.getLineStart(lastLine); - int end = layout.getLineEnd(lastLine); - float lineWidth = layout.getLineWidth(lastLine); - float ellipseWidth = textPaint.measureText(mEllipsis); + } - // Trim characters off until we have enough room to draw the ellipsis - while(width < lineWidth + ellipseWidth) { - lineWidth = textPaint.measureText(text.subSequence(start, --end + 1).toString()); - } - setText(text.subSequence(0, end) + mEllipsis); + // Some devices try to auto adjust line spacing, so force default line spacing + // and invalidate the layout as a side effect + textPaint.setTextSize(newTextSize); + //setLineSpacing(spacingAdd, spacingMult); - } + // Notify the listener if registered + if (mTextResizeListener != null) { + mTextResizeListener.onTextResize(this, oldTextSize, newTextSize); + } - // Some devices try to auto adjust line spacing, so force default line spacing - // and invalidate the layout as a side effect - textPaint.setTextSize(targetTextSize); - setLineSpacing(mSpacingAdd, mSpacingMult); - - // Notify the listener if registered - if(mTextResizeListener != null) { - mTextResizeListener.onTextResize(this, oldTextSize, targetTextSize); - } - - // Reset force resize flag - mNeedsResize = false; - } - - // Set the text size of the text paint object and use a static layout to render text off screen before measuring - private int getTextHeight(CharSequence source, TextPaint paint, int width, float textSize) { - // Update the text paint object - paint.setTextSize(textSize); - // Draw using a static layout - StaticLayout layout = new StaticLayout(source, paint, width, Alignment.ALIGN_NORMAL, mSpacingMult, mSpacingAdd, false); - layout.draw(sTextResizeCanvas); - return layout.getHeight(); - } + // Reset force resize flag + mNeedsResize = false; + } + // Set the text size of the text paint object and use a static layout to render text off screen before measuring + private int getTextRect(CharSequence source, TextPaint paint, int width, float textSize) { + // Update the text paint object + paint.setTextSize(textSize); + // Draw using a static layout + StaticLayout layout = new StaticLayout(source, paint, width, Alignment.ALIGN_NORMAL, spacingMult, spacingAdd, false); + layout.draw(sTextResizeCanvas); + return layout.getHeight(); + } }