Last active
May 3, 2016 23:45
-
-
Save haroldolivieri/282831e2fef2cae3c5b8 to your computer and use it in GitHub Desktop.
A resizable textview with animation that depends on screen width and decreases in relation to stepTextSize attribute
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<resources xmlns:android="http://schemas.android.com/apk/res/android"> | |
<declare-styleable name="ResizableTextView"> | |
<attr name="minTextSize" format="dimension" /> | |
<attr name="maxTextSize" format="dimension" /> | |
<attr name="stepTextSize" format="dimension" /> | |
</declare-styleable> | |
</resources> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<ResizableTextView | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:gravity="bottom|right" | |
android:enabled="false" | |
android:textAlignment="textEnd" | |
android:maxLines="1" | |
minTextSize="36sp" | |
maxTextSize="64sp" | |
stepTextSize="8sp"/> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class ResizableTextView extends TextView { | |
private final float mMaximumTextSize; | |
private final float mMinimumTextSize; | |
private final float mStepTextSize; | |
private final Paint mTempPaint = new TextPaint(); | |
private final Rect mTempRect = new Rect(); | |
private int mWidthConstraint = -1; | |
private OnTextSizeChangeListener mOnTextSizeChangeListener; | |
public ResizableTextView(Context context) { | |
this(context, null); | |
} | |
public ResizableTextView(Context context, AttributeSet attrs) { | |
this(context, attrs, 0); | |
} | |
public ResizableTextView(Context context, AttributeSet attrs, int defStyle) { | |
super(context, attrs, defStyle); | |
final TypedArray a = context.obtainStyledAttributes( | |
attrs, R.styleable.ResizableTextView, defStyle, 0); | |
mMaximumTextSize = a.getDimension( | |
R.styleable.ResizableTextView_maxTextSize, getTextSize()); | |
mMinimumTextSize = a.getDimension( | |
R.styleable.ResizableTextView_minTextSize, getTextSize()); | |
mStepTextSize = a.getDimension(R.styleable.ResizableTextView_stepTextSize, | |
(mMaximumTextSize - mMinimumTextSize) / 3); | |
a.recycle(); | |
if (isFocusable()) { | |
setMovementMethod(ScrollingMovementMethod.getInstance()); | |
} | |
setTextSize(TypedValue.COMPLEX_UNIT_PX, mMaximumTextSize); | |
setMinHeight(getLineHeight() + getCompoundPaddingBottom() + getCompoundPaddingTop()); | |
} | |
@Override | |
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | |
super.onMeasure(widthMeasureSpec, heightMeasureSpec); | |
mWidthConstraint = | |
MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight(); | |
setTextSize(TypedValue.COMPLEX_UNIT_PX, getVariableTextSize(getText().toString())); | |
} | |
@Override | |
protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) { | |
super.onTextChanged(text, start, lengthBefore, lengthAfter); | |
setTextSize(TypedValue.COMPLEX_UNIT_PX, getVariableTextSize(text.toString())); | |
} | |
@Override | |
public void setTextSize(int unit, float size) { | |
final float oldTextSize = getTextSize(); | |
super.setTextSize(unit, size); | |
if (mOnTextSizeChangeListener != null && getTextSize() != oldTextSize) { | |
mOnTextSizeChangeListener.onTextSizeChanged(this, oldTextSize); | |
} | |
} | |
public void setOnTextSizeChangeListener(OnTextSizeChangeListener listener) { | |
mOnTextSizeChangeListener = listener; | |
} | |
public float getVariableTextSize(String text) { | |
if (mWidthConstraint < 0 || mMaximumTextSize <= mMinimumTextSize) { | |
return getTextSize(); | |
} | |
mTempPaint.set(getPaint()); | |
float lastFitTextSize = mMinimumTextSize; | |
while (lastFitTextSize < mMaximumTextSize) { | |
final float nextSize = Math.min(lastFitTextSize + mStepTextSize, mMaximumTextSize); | |
mTempPaint.setTextSize(nextSize); | |
if (mTempPaint.measureText(text) > mWidthConstraint) { | |
break; | |
} else { | |
lastFitTextSize = nextSize; | |
} | |
} | |
return lastFitTextSize; | |
} | |
@Override | |
public int getCompoundPaddingTop() { | |
getPaint().getTextBounds("H", 0, 1, mTempRect); | |
final Paint.FontMetricsInt fontMetrics = getPaint().getFontMetricsInt(); | |
final int paddingOffset = -(fontMetrics.ascent + mTempRect.height()); | |
return super.getCompoundPaddingTop() - Math.min(getPaddingTop(), paddingOffset); | |
} | |
@Override | |
public int getCompoundPaddingBottom() { | |
final Paint.FontMetricsInt fontMetrics = getPaint().getFontMetricsInt(); | |
return super.getCompoundPaddingBottom() - Math.min(getPaddingBottom(), fontMetrics.descent); | |
} | |
public interface OnTextSizeChangeListener { | |
void onTextSizeChanged(TextView textView, float oldSize); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Override | |
public void onTextSizeChanged(TextView textView, float oldSize) { | |
final float textScale = oldSize / textView.getTextSize(); | |
final float translationX = (1.0f - textScale) * | |
(textView.getWidth() / 2.0f - textView.getPaddingEnd()); | |
final float translationY = (1.0f - textScale) * | |
(textView.getHeight() / 2.0f - textView.getPaddingBottom()); | |
final AnimatorSet animatorSet = new AnimatorSet(); | |
animatorSet.playTogether( | |
ObjectAnimator.ofFloat(textView, View.SCALE_X, textScale, 1.0f), | |
ObjectAnimator.ofFloat(textView, View.SCALE_Y, textScale, 1.0f), | |
ObjectAnimator.ofFloat(textView, View.TRANSLATION_X, translationX, 0.0f), | |
ObjectAnimator.ofFloat(textView, View.TRANSLATION_Y, translationY, 0.0f)); | |
animatorSet.setDuration(getResources().getInteger(android.R.integer.config_mediumAnimTime)); | |
animatorSet.setInterpolator(new AccelerateDecelerateInterpolator()); | |
animatorSet.start(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment