Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 66 additions & 10 deletions library/src/main/java/me/grantland/widget/AutofitHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ public static AutofitHelper create(TextView view, AttributeSet attrs) {
public static AutofitHelper create(TextView view, AttributeSet attrs, int defStyle) {
AutofitHelper helper = new AutofitHelper(view);
boolean sizeToFit = true;
boolean heightToFit = false;
if (attrs != null) {
Context context = view.getContext();
int minTextSize = (int) helper.getMinTextSize();
Expand All @@ -72,14 +73,16 @@ public static AutofitHelper create(TextView view, AttributeSet attrs, int defSty
defStyle,
0);
sizeToFit = ta.getBoolean(R.styleable.AutofitTextView_sizeToFit, sizeToFit);
heightToFit = ta.getBoolean(R.styleable.AutofitTextView_heightToFit, heightToFit);
minTextSize = ta.getDimensionPixelSize(R.styleable.AutofitTextView_minTextSize,
minTextSize);
precision = ta.getFloat(R.styleable.AutofitTextView_precision, precision);
ta.recycle();

helper.setMinTextSize(TypedValue.COMPLEX_UNIT_PX, minTextSize)
.setPrecision(precision);
.setPrecision(precision);
}
helper.setHeightFitting(heightToFit);
helper.setEnabled(sizeToFit);

return helper;
Expand All @@ -89,7 +92,7 @@ public static AutofitHelper create(TextView view, AttributeSet attrs, int defSty
* Re-sizes the textSize of the TextView so that the text fits within the bounds of the View.
*/
private static void autofit(TextView view, TextPaint paint, float minTextSize, float maxTextSize,
int maxLines, float precision) {
int maxLines, float precision) {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: revert

if (maxLines <= 0 || maxLines == Integer.MAX_VALUE) {
// Don't auto-size since there's no limit on lines.
return;
Expand Down Expand Up @@ -128,19 +131,49 @@ private static void autofit(TextView view, TextPaint paint, float minTextSize, f
displayMetrics);
}

if (size < minTextSize) {
size = minTextSize;
if (mIsHeightFitting) {
int targetHeight = view.getHeight() - view.getPaddingTop() - view.getPaddingBottom();
if (targetHeight <= 0) {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seems like we could invert this conditional so that we don't have to duplicate minTextSize check and setTextSize calls

if (size < minTextSize) {
size = minTextSize;
}
view.setTextSize(TypedValue.COMPLEX_UNIT_PX, size);
return;
}

float textHeight = getTextHeight(text, paint, targetWidth, size);
float heightRatio = targetHeight / textHeight;
float newSize = size * heightRatio;
if (newSize < size) {
size = newSize;
}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this method of calculating a fitting textSize to match the height is interesting and different than how we calculate fitting textSize to match the width... are we guaranteed that text height changes proportionally with textSize? if we are, could we use a similar method for width? if not, should we use a similar procedure?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm actually not super familiar with StaticLayout; that's just what KonradJanica used to calculate height. However, I think this article on The Mathematics of Golden Ratio Typography sheds some light on the mathematics between text height, text width, and text size.


if (size < minTextSize) {
size = minTextSize;
}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to pop this conditional out of it's nested conditional or else we'll break minTextSize for non-height-fitting modes

}

view.setTextSize(TypedValue.COMPLEX_UNIT_PX, size);
}

/**
* Try to fit the text with current size to a static layout to calculate height needed
* by that text size.
* @note Can be put in a loop where text size is gradually decreased etc.
* @return float The height size required by the text.
*/
private static float getTextHeight(CharSequence text, TextPaint paint, int width, float textSize) {
StaticLayout textHeightAdjuster = new StaticLayout(text, paint, width,
Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, true);
return textHeightAdjuster.getHeight();
}

/**
* Recursive binary search to find the best size for the text.
*/
private static float getAutofitTextSize(CharSequence text, TextPaint paint,
float targetWidth, int maxLines, float low, float high, float precision,
DisplayMetrics displayMetrics) {
float targetWidth, int maxLines, float low, float high, float precision,
DisplayMetrics displayMetrics) {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: revert

float mid = (low + high) / 2.0f;
int lineCount = 1;
StaticLayout layout = null;
Expand Down Expand Up @@ -196,7 +229,7 @@ else if (lineCount < maxLines) {
}

private static int getLineCount(CharSequence text, TextPaint paint, float size, float width,
DisplayMetrics displayMetrics) {
DisplayMetrics displayMetrics) {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: revert

paint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, size,
displayMetrics));
StaticLayout layout = new StaticLayout(text, paint, (int)width,
Expand Down Expand Up @@ -234,6 +267,7 @@ else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {

private boolean mEnabled;
private boolean mIsAutofitting;
private static boolean mIsHeightFitting;

private ArrayList<OnTextSizeChangeListener> mListeners;

Expand Down Expand Up @@ -418,7 +452,8 @@ public AutofitHelper setMaxLines(int lines) {
}

/**
* Returns whether or not automatically resizing text is enabled.
* Returns whether or not automatically resizing text
* by width and number of lines is enabled.
*/
public boolean isEnabled() {
return mEnabled;
Expand Down Expand Up @@ -446,6 +481,27 @@ public AutofitHelper setEnabled(boolean enabled) {
return this;
}

/**
* Returns whether or not automatically resizing text
* by height is enabled.
* @return boolean True when height scaling is on.
*/
public boolean isHeightFitting() {
return mIsHeightFitting;
}

/**
* Sets the state of automatically resizing by text fitting in height.
* Calls an autofit if it is already enabled.
* @param enabled The state to update the height fitting member
*/
public AutofitHelper setHeightFitting(boolean enabled) {
mIsHeightFitting = enabled;
// Fit if required
setEnabled(mEnabled);
return this;
}

/**
* Returns the original text size of the View.
*
Expand Down Expand Up @@ -535,7 +591,7 @@ public void afterTextChanged(Editable editable) {
private class AutofitOnLayoutChangeListener implements View.OnLayoutChangeListener {
@Override
public void onLayoutChange(View view, int left, int top, int right, int bottom,
int oldLeft, int oldTop, int oldRight, int oldBottom) {
int oldLeft, int oldTop, int oldRight, int oldBottom) {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: revert

autofit();
}
}
Expand All @@ -551,4 +607,4 @@ public interface OnTextSizeChangeListener {
*/
public void onTextSizeChange(float textSize, float oldTextSize);
}
}
}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: revert

11 changes: 8 additions & 3 deletions library/src/main/java/me/grantland/widget/AutofitLayout.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
public class AutofitLayout extends FrameLayout {

private boolean mEnabled;
private boolean mIsHeightFitting;
private float mMinTextSize;
private float mPrecision;
private WeakHashMap<View, AutofitHelper> mHelpers = new WeakHashMap<View, AutofitHelper>();
Expand All @@ -43,6 +44,7 @@ public AutofitLayout(Context context, AttributeSet attrs, int defStyle) {

private void init(Context context, AttributeSet attrs, int defStyle) {
boolean sizeToFit = true;
boolean heightToFit = false;
int minTextSize = -1;
float precision = -1;

Expand All @@ -53,13 +55,15 @@ private void init(Context context, AttributeSet attrs, int defStyle) {
defStyle,
0);
sizeToFit = ta.getBoolean(R.styleable.AutofitTextView_sizeToFit, sizeToFit);
heightToFit = ta.getBoolean(R.styleable.AutofitTextView_heightToFit, heightToFit);
minTextSize = ta.getDimensionPixelSize(R.styleable.AutofitTextView_minTextSize,
minTextSize);
precision = ta.getFloat(R.styleable.AutofitTextView_precision, precision);
ta.recycle();
}

mEnabled = sizeToFit;
mIsHeightFitting = heightToFit;
mMinTextSize = minTextSize;
mPrecision = precision;
}
Expand All @@ -68,8 +72,9 @@ private void init(Context context, AttributeSet attrs, int defStyle) {
public void addView(View child, int index, ViewGroup.LayoutParams params) {
super.addView(child, index, params);
TextView textView = (TextView) child;
AutofitHelper helper = AutofitHelper.create(textView)
.setEnabled(mEnabled);
AutofitHelper helper = AutofitHelper.create(textView);
helper.setHeightFitting(mIsHeightFitting);
helper.setEnabled(mEnabled);
if (mPrecision > 0) {
helper.setPrecision(mPrecision);
}
Expand All @@ -92,4 +97,4 @@ public AutofitHelper getAutofitHelper(TextView textView) {
public AutofitHelper getAutofitHelper(int index) {
return mHelpers.get(getChildAt(index));
}
}
}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: revert

25 changes: 24 additions & 1 deletion library/src/main/java/me/grantland/widget/AutofitTextView.java
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,29 @@ public void setSizeToFit(boolean sizeToFit) {
mHelper.setEnabled(sizeToFit);
}

/**
* Returns whether or not the text will be automatically re-sized to fit its height.
*/
public boolean isHeightFitting() {
return mHelper.isHeightFitting();
}

/**
* Sets the property of this field (isHeightFitting), to automatically resize the text to fit
* its height.
*/
public void setHeightFitting() {
setHeightFitting(true);
}

/**
* Enables automatic text resizing to fit the textview height
* @param isEnabled If true, the text will automatically be re-sized to fit its height
*/
public void setHeightFitting(boolean isEnabled) {
mHelper.setHeightFitting(isEnabled);
}

/**
* Returns the maximum size (in pixels) of the text in this View.
*/
Expand Down Expand Up @@ -189,4 +212,4 @@ public void setPrecision(float precision) {
public void onTextSizeChange(float textSize, float oldTextSize) {
// do nothing
}
}
}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: revert

2 changes: 2 additions & 0 deletions library/src/main/res/values/attrs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@
<attr name="precision" format="float" />
<!-- Defines whether to automatically resize text to fit to the view's bounds. -->
<attr name="sizeToFit" format="boolean" />
<!-- Defines whether to automatically resize text to fit to the view's height bounds. -->
<attr name="heightToFit" format="boolean" />
</declare-styleable>
</resources>