以下是带有自定义字体功能的avalancha TextView。
用法:
<?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>
不要忘记添加:xmlns:foo="http://schemas.android.com/apk/res-auto"。字体应该在assets目录中。
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;
@SuppressWarnings("unused")
public class AutoFitText extends TextView {
private static final String TAG = AutoFitText.class.getSimpleName();
private final int MIN_TEXT_SIZE = 10;
private final int MAX_TEXT_SIZE = 400;
private boolean mSingleLine = false;
private TextView mTestView;
private Paint mTestPaint;
private float mScaledDensityFactor;
private final float mThreshold = 0.5f;
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) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AutoFitText);
String customFont = a.getString(R.styleable.AutoFitText_customFont);
setCustomFont(context, customFont);
a.recycle();
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() {
onSizeChanged(AutoFitText.this.getWidth(), AutoFitText.this.getHeight(), 0, 0);
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);
}
}
private void refitText(String text, int targetFieldWidth, int targetFieldHeight) {
float lowerTextSize = MIN_TEXT_SIZE;
float upperTextSize = MAX_TEXT_SIZE;
this.setMaxWidth(targetFieldWidth);
targetFieldWidth = targetFieldWidth - this.getPaddingLeft() - this.getPaddingRight();
targetFieldHeight = targetFieldHeight - this.getPaddingTop() - this.getPaddingBottom();
mTestView.setLayoutParams(new LayoutParams(targetFieldWidth, targetFieldHeight));
mTestView.setMaxWidth(targetFieldWidth);
if (mSingleLine) {
for (float testSize; (upperTextSize - lowerTextSize) > mThreshold;) {
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;
} else {
lowerTextSize = testSize;
}
}
mTestView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
if (mTestView.getMeasuredHeight() > targetFieldHeight) {
upperTextSize = lowerTextSize;
lowerTextSize = MIN_TEXT_SIZE;
for (float testSize; (upperTextSize - lowerTextSize) > mThreshold;) {
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;
} else {
lowerTextSize = testSize;
}
}
}
} else {
for (float testSize; (upperTextSize - lowerTextSize) > mThreshold;) {
testSize = (upperTextSize + lowerTextSize) / 2;
mTestView.setTextSize(TypedValue.COMPLEX_UNIT_SP, testSize / mScaledDensityFactor);
mTestView.setText(text);
mTestView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
int tempHeight = mTestView.getMeasuredHeight();
if (tempHeight >= targetFieldHeight) {
upperTextSize = testSize;
} else {
lowerTextSize = testSize;
}
}
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>();
}
}
}
this.setTextSize(TypedValue.COMPLEX_UNIT_SP, lowerTextSize / mScaledDensityFactor);
return;
}
@Override
protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
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);
}
}
@Override
public void setText(CharSequence text, BufferType type) {
int targetFieldWidth = this.getWidth();
int targetFieldHeight = this.getHeight();
if (targetFieldWidth <= 0 || targetFieldHeight <= 0 || text.equals("")) {
} else {
refitText(text.toString(), targetFieldWidth, targetFieldHeight);
}
super.setText(text, type);
}
@Override
public void setMaxLines(int maxLines) {
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) {
mSingleLine = singleLine;
super.setSingleLine(singleLine);
}
}
已知的问题:
无法在Android 4.03上工作-字体不可见或非常小(原始avalancha也无法工作)
以下是解决该问题的方法:https://dev59.com/7WQo5IYBdhLWcg3wfPUa#21851239
android:maxLines="1"
与android:gravity="center_vertical"
(垂直居中)似乎存在冲突(垂直居中未应用)。 - matoni