安卓AutoFitTextView实例Dmeo分享自适应
来源:互联网 发布:淘宝上的呼死你叫什么 编辑:程序博客网 时间:2024/06/10 11:16
一、首先看看运行效果图:
二、主要核心类:
1、AutofitHelper.java
2、AutofitLayout.java
3、AutofitTextView.java
以上为主要核心类,直接在MainActivity.java类里面使用以及布局中使用,详情看代码:
AutofitHelper.java
package com.example.demo;import android.annotation.SuppressLint;import android.content.Context;import android.content.res.Resources;import android.content.res.TypedArray;import android.os.Build;import android.text.Editable;import android.text.Layout;import android.text.StaticLayout;import android.text.TextPaint;import android.text.TextWatcher;import android.text.method.SingleLineTransformationMethod;import android.text.method.TransformationMethod;import android.util.AttributeSet;import android.util.DisplayMetrics;import android.util.Log;import android.util.TypedValue;import android.view.View;import android.widget.TextView;import java.util.ArrayList;/** * A helper class to enable automatically resizing {@link TextView}`s {@code textSize} to fit * within its bounds. * * @attr ref R.styleable.AutofitTextView_sizeToFit * @attr ref R.styleable.AutofitTextView_minTextSize * @attr ref R.styleable.AutofitTextView_precision */public class AutofitHelper { private static final String TAG = "AutoFitTextHelper"; private static final boolean SPEW = false; // Minimum size of the text in pixels private static final int DEFAULT_MIN_TEXT_SIZE = 8; //sp // How precise we want to be when reaching the target textWidth size private static final float DEFAULT_PRECISION = 0.5f; /** * Creates a new instance of {@code AutofitHelper} that wraps a {@link TextView} and enables * automatically sizing the text to fit. */ public static AutofitHelper create(TextView view) { return create(view, null, 0); } /** * Creates a new instance of {@code AutofitHelper} that wraps a {@link TextView} and enables * automatically sizing the text to fit. */ public static AutofitHelper create(TextView view, AttributeSet attrs) { return create(view, attrs, 0); } /** * Creates a new instance of {@code AutofitHelper} that wraps a {@link TextView} and enables * automatically sizing the text to fit. */ public static AutofitHelper create(TextView view, AttributeSet attrs, int defStyle) { AutofitHelper helper = new AutofitHelper(view); boolean sizeToFit = true; if (attrs != null) { Context context = view.getContext(); int minTextSize = (int) helper.getMinTextSize(); float precision = helper.getPrecision(); TypedArray ta = context.obtainStyledAttributes( attrs, R.styleable.AutofitTextView, defStyle, 0); sizeToFit = ta.getBoolean(R.styleable.AutofitTextView_sizeToFit, sizeToFit); 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); } helper.setEnabled(sizeToFit); return helper; } /** * 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) { if (maxLines <= 0 || maxLines == Integer.MAX_VALUE) { // Don't auto-size since there's no limit on lines. return; } int targetWidth = view.getWidth() - view.getPaddingLeft() - view.getPaddingRight(); if (targetWidth <= 0) { return; } CharSequence text = view.getText(); TransformationMethod method = view.getTransformationMethod(); if (method != null) { text = method.getTransformation(text, view); } Context context = view.getContext(); Resources r = Resources.getSystem(); DisplayMetrics displayMetrics; float size = maxTextSize; float high = size; float low = 0; if (context != null) { r = context.getResources(); } displayMetrics = r.getDisplayMetrics(); paint.set(view.getPaint()); paint.setTextSize(size); if ((maxLines == 1 && paint.measureText(text, 0, text.length()) > targetWidth) || getLineCount(text, paint, size, targetWidth, displayMetrics) > maxLines) { size = getAutofitTextSize(text, paint, targetWidth, maxLines, low, high, precision, displayMetrics); } if (size < minTextSize) { size = minTextSize; } view.setTextSize(TypedValue.COMPLEX_UNIT_PX, size); } /** * 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 mid = (low + high) / 2.0f; int lineCount = 1; StaticLayout layout = null; paint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, mid, displayMetrics)); if (maxLines != 1) { layout = new StaticLayout(text, paint, (int)targetWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, true); lineCount = layout.getLineCount(); } if (SPEW) Log.d(TAG, "low=" + low + " high=" + high + " mid=" + mid + " target=" + targetWidth + " maxLines=" + maxLines + " lineCount=" + lineCount); if (lineCount > maxLines) { // For the case that `text` has more newline characters than `maxLines`. if ((high - low) < precision) { return low; } return getAutofitTextSize(text, paint, targetWidth, maxLines, low, mid, precision, displayMetrics); } else if (lineCount < maxLines) { return getAutofitTextSize(text, paint, targetWidth, maxLines, mid, high, precision, displayMetrics); } else { float maxLineWidth = 0; if (maxLines == 1) { maxLineWidth = paint.measureText(text, 0, text.length()); } else { for (int i = 0; i < lineCount; i++) { if (layout.getLineWidth(i) > maxLineWidth) { maxLineWidth = layout.getLineWidth(i); } } } if ((high - low) < precision) { return low; } else if (maxLineWidth > targetWidth) { return getAutofitTextSize(text, paint, targetWidth, maxLines, low, mid, precision, displayMetrics); } else if (maxLineWidth < targetWidth) { return getAutofitTextSize(text, paint, targetWidth, maxLines, mid, high, precision, displayMetrics); } else { return mid; } } } private static int getLineCount(CharSequence text, TextPaint paint, float size, float width, DisplayMetrics displayMetrics) { paint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, size, displayMetrics)); StaticLayout layout = new StaticLayout(text, paint, (int)width, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, true); return layout.getLineCount(); } private static int getMaxLines(TextView view) { int maxLines = -1; // No limit (Integer.MAX_VALUE also means no limit) TransformationMethod method = view.getTransformationMethod(); if (method != null && method instanceof SingleLineTransformationMethod) { maxLines = 1; } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { // setMaxLines() and getMaxLines() are only available on android-16+ maxLines = view.getMaxLines(); } return maxLines; } // Attributes private TextView mTextView; private TextPaint mPaint; /** * Original textSize of the TextView. */ private float mTextSize; private int mMaxLines; private float mMinTextSize; private float mMaxTextSize; private float mPrecision; private boolean mEnabled; private boolean mIsAutofitting; private ArrayList<OnTextSizeChangeListener> mListeners; private TextWatcher mTextWatcher = new AutofitTextWatcher(); private View.OnLayoutChangeListener mOnLayoutChangeListener = new AutofitOnLayoutChangeListener(); private AutofitHelper(TextView view) { final Context context = view.getContext(); float scaledDensity = context.getResources().getDisplayMetrics().scaledDensity; mTextView = view; mPaint = new TextPaint(); setRawTextSize(view.getTextSize()); mMaxLines = getMaxLines(view); mMinTextSize = scaledDensity * DEFAULT_MIN_TEXT_SIZE; mMaxTextSize = mTextSize; mPrecision = DEFAULT_PRECISION; } /** * Adds an {@link OnTextSizeChangeListener} to the list of those whose methods are called * whenever the {@link TextView}'s {@code textSize} changes. */ public AutofitHelper addOnTextSizeChangeListener(OnTextSizeChangeListener listener) { if (mListeners == null) { mListeners = new ArrayList<OnTextSizeChangeListener>(); } mListeners.add(listener); return this; } /** * Removes the specified {@link OnTextSizeChangeListener} from the list of those whose methods * are called whenever the {@link TextView}'s {@code textSize} changes. */ public AutofitHelper removeOnTextSizeChangeListener(OnTextSizeChangeListener listener) { if (mListeners != null) { mListeners.remove(listener); } return this; } /** * Returns the amount of precision used to calculate the correct text size to fit within its * bounds. */ public float getPrecision() { return mPrecision; } /** * Set the amount of precision used to calculate the correct text size to fit within its * bounds. Lower precision is more precise and takes more time. * * @param precision The amount of precision. */ public AutofitHelper setPrecision(float precision) { if (mPrecision != precision) { mPrecision = precision; autofit(); } return this; } /** * Returns the minimum size (in pixels) of the text. */ public float getMinTextSize() { return mMinTextSize; } /** * Set the minimum text size to the given value, interpreted as "scaled pixel" units. This size * is adjusted based on the current density and user font size preference. * * @param size The scaled pixel size. * * @attr ref me.grantland.R.styleable#AutofitTextView_minTextSize */ public AutofitHelper setMinTextSize(float size) { return setMinTextSize(TypedValue.COMPLEX_UNIT_SP, size); } /** * Set the minimum text size to a given unit and value. See TypedValue for the possible * dimension units. * * @param unit The desired dimension unit. * @param size The desired size in the given units. * * @attr ref me.grantland.R.styleable#AutofitTextView_minTextSize */ public AutofitHelper setMinTextSize(int unit, float size) { Context context = mTextView.getContext(); Resources r = Resources.getSystem(); if (context != null) { r = context.getResources(); } setRawMinTextSize(TypedValue.applyDimension(unit, size, r.getDisplayMetrics())); return this; } private void setRawMinTextSize(float size) { if (size != mMinTextSize) { mMinTextSize = size; autofit(); } } /** * Returns the maximum size (in pixels) of the text. */ public float getMaxTextSize() { return mMaxTextSize; } /** * Set the maximum text size to the given value, interpreted as "scaled pixel" units. This size * is adjusted based on the current density and user font size preference. * * @param size The scaled pixel size. * * @attr ref android.R.styleable#TextView_textSize */ public AutofitHelper setMaxTextSize(float size) { return setMaxTextSize(TypedValue.COMPLEX_UNIT_SP, size); } /** * Set the maximum text size to a given unit and value. See TypedValue for the possible * dimension units. * * @param unit The desired dimension unit. * @param size The desired size in the given units. * * @attr ref android.R.styleable#TextView_textSize */ public AutofitHelper setMaxTextSize(int unit, float size) { Context context = mTextView.getContext(); Resources r = Resources.getSystem(); if (context != null) { r = context.getResources(); } setRawMaxTextSize(TypedValue.applyDimension(unit, size, r.getDisplayMetrics())); return this; } private void setRawMaxTextSize(float size) { if (size != mMaxTextSize) { mMaxTextSize = size; autofit(); } } /** * @see TextView#getMaxLines() */ public int getMaxLines() { return mMaxLines; } /** * @see TextView#setMaxLines(int) */ public AutofitHelper setMaxLines(int lines) { if (mMaxLines != lines) { mMaxLines = lines; autofit(); } return this; } /** * Returns whether or not automatically resizing text is enabled. */ public boolean isEnabled() { return mEnabled; } /** * Set the enabled state of automatically resizing text. */ @SuppressLint("NewApi")public AutofitHelper setEnabled(boolean enabled) { if (mEnabled != enabled) { mEnabled = enabled; if (enabled) { mTextView.addTextChangedListener(mTextWatcher); mTextView.addOnLayoutChangeListener(mOnLayoutChangeListener); autofit(); } else { mTextView.removeTextChangedListener(mTextWatcher); mTextView.removeOnLayoutChangeListener(mOnLayoutChangeListener); mTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize); } } return this; } /** * Returns the original text size of the View. * * @see TextView#getTextSize() */ public float getTextSize() { return mTextSize; } /** * Set the original text size of the View. * * @see TextView#setTextSize(float) */ public void setTextSize(float size) { setTextSize(TypedValue.COMPLEX_UNIT_SP, size); } /** * Set the original text size of the View. * * @see TextView#setTextSize(int, float) */ public void setTextSize(int unit, float size) { if (mIsAutofitting) { // We don't want to update the TextView's actual textSize while we're autofitting // since it'd get set to the autofitTextSize return; } Context context = mTextView.getContext(); Resources r = Resources.getSystem(); if (context != null) { r = context.getResources(); } setRawTextSize(TypedValue.applyDimension(unit, size, r.getDisplayMetrics())); } private void setRawTextSize(float size) { if (mTextSize != size) { mTextSize = size; } } private void autofit() { float oldTextSize = mTextView.getTextSize(); float textSize; mIsAutofitting = true; autofit(mTextView, mPaint, mMinTextSize, mMaxTextSize, mMaxLines, mPrecision); mIsAutofitting = false; textSize = mTextView.getTextSize(); if (textSize != oldTextSize) { sendTextSizeChange(textSize, oldTextSize); } } private void sendTextSizeChange(float textSize, float oldTextSize) { if (mListeners == null) { return; } for (OnTextSizeChangeListener listener : mListeners) { listener.onTextSizeChange(textSize, oldTextSize); } } private class AutofitTextWatcher implements TextWatcher { @Override public void beforeTextChanged(CharSequence charSequence, int start, int count, int after) { // do nothing } @Override public void onTextChanged(CharSequence charSequence, int start, int before, int count) { autofit(); } @Override public void afterTextChanged(Editable editable) { // do nothing } } @SuppressLint("NewApi")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) { autofit(); } } /** * When an object of a type is attached to an {@code AutofitHelper}, its methods will be called * when the {@code textSize} is changed. */ public interface OnTextSizeChangeListener { /** * This method is called to notify you that the size of the text has changed to * {@code textSize} from {@code oldTextSize}. */ public void onTextSizeChange(float textSize, float oldTextSize); }}
AutofitLayout.java:
package com.example.demo;import android.content.Context;import android.content.res.TypedArray;import android.util.AttributeSet;import android.util.TypedValue;import android.view.View;import android.view.ViewGroup;import android.widget.FrameLayout;import android.widget.TextView;import java.util.WeakHashMap;/** * A {@link ViewGroup} that re-sizes the text of it's children to be no larger than the width of the * view. * * @attr ref R.styleable.AutofitTextView_sizeToFit * @attr ref R.styleable.AutofitTextView_minTextSize * @attr ref R.styleable.AutofitTextView_precision */public class AutofitLayout extends FrameLayout { private boolean mEnabled; private float mMinTextSize; private float mPrecision; private WeakHashMap<View, AutofitHelper> mHelpers = new WeakHashMap<View, AutofitHelper>(); public AutofitLayout(Context context) { super(context); init(context, null, 0); } public AutofitLayout(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs, 0); } public AutofitLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context, attrs, defStyle); } private void init(Context context, AttributeSet attrs, int defStyle) { boolean sizeToFit = true; int minTextSize = -1; float precision = -1; if (attrs != null) { TypedArray ta = context.obtainStyledAttributes( attrs, R.styleable.AutofitTextView, defStyle, 0); sizeToFit = ta.getBoolean(R.styleable.AutofitTextView_sizeToFit, sizeToFit); minTextSize = ta.getDimensionPixelSize(R.styleable.AutofitTextView_minTextSize, minTextSize); precision = ta.getFloat(R.styleable.AutofitTextView_precision, precision); ta.recycle(); } mEnabled = sizeToFit; mMinTextSize = minTextSize; mPrecision = precision; } @Override 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); if (mPrecision > 0) { helper.setPrecision(mPrecision); } if (mMinTextSize > 0) { helper.setMinTextSize(TypedValue.COMPLEX_UNIT_PX, mMinTextSize); } mHelpers.put(textView, helper); } /** * Returns the {@link AutofitHelper} for this child View. */ public AutofitHelper getAutofitHelper(TextView textView) { return mHelpers.get(textView); } /** * Returns the {@link AutofitHelper} for this child View. */ public AutofitHelper getAutofitHelper(int index) { return mHelpers.get(getChildAt(index)); }}
AutofitTextView.java:
package com.example.demo;import android.content.Context;import android.util.AttributeSet;import android.util.TypedValue;import android.widget.TextView;/** * A {@link TextView} that re-sizes its text to be no larger than the width of the view. * 自定义AutofitTextView类 * @attr ref R.styleable.AutofitTextView_sizeToFit * @attr ref R.styleable.AutofitTextView_minTextSize * @attr ref R.styleable.AutofitTextView_precision */public class AutofitTextView extends TextView implements AutofitHelper.OnTextSizeChangeListener { private AutofitHelper mHelper; public AutofitTextView(Context context) { super(context); init(context, null, 0); } public AutofitTextView(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs, 0); } public AutofitTextView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context, attrs, defStyle); } private void init(Context context, AttributeSet attrs, int defStyle) { mHelper = AutofitHelper.create(this, attrs, defStyle) .addOnTextSizeChangeListener(this); } // Getters and Setters /** * {@inheritDoc} */ @Override public void setTextSize(int unit, float size) { super.setTextSize(unit, size); if (mHelper != null) { mHelper.setTextSize(unit, size); } } /** * {@inheritDoc} */ @Override public void setLines(int lines) { super.setLines(lines); if (mHelper != null) { mHelper.setMaxLines(lines); } } /** * {@inheritDoc} */ @Override public void setMaxLines(int maxLines) { super.setMaxLines(maxLines); if (mHelper != null) { mHelper.setMaxLines(maxLines); } } /** * Returns the {@link AutofitHelper} for this View. */ public AutofitHelper getAutofitHelper() { return mHelper; } /** * Returns whether or not the text will be automatically re-sized to fit its constraints. */ public boolean isSizeToFit() { return mHelper.isEnabled(); } /** * Sets the property of this field (sizeToFit), to automatically resize the text to fit its * constraints. */ public void setSizeToFit() { setSizeToFit(true); } /** * If true, the text will automatically be re-sized to fit its constraints; if false, it will * act like a normal TextView. * * @param sizeToFit */ public void setSizeToFit(boolean sizeToFit) { mHelper.setEnabled(sizeToFit); } /** * Returns the maximum size (in pixels) of the text in this View. */ public float getMaxTextSize() { return mHelper.getMaxTextSize(); } /** * Set the maximum text size to the given value, interpreted as "scaled pixel" units. This size * is adjusted based on the current density and user font size preference. * * @param size The scaled pixel size. * * @attr ref android.R.styleable#TextView_textSize */ public void setMaxTextSize(float size) { mHelper.setMaxTextSize(size); } /** * Set the maximum text size to a given unit and value. See TypedValue for the possible * dimension units. * * @param unit The desired dimension unit. * @param size The desired size in the given units. * * @attr ref android.R.styleable#TextView_textSize */ public void setMaxTextSize(int unit, float size) { mHelper.setMaxTextSize(unit, size); } /** * Returns the minimum size (in pixels) of the text in this View. */ public float getMinTextSize() { return mHelper.getMinTextSize(); } /** * Set the minimum text size to the given value, interpreted as "scaled pixel" units. This size * is adjusted based on the current density and user font size preference. * * @param minSize The scaled pixel size. * * @attr ref me.grantland.R.styleable#AutofitTextView_minTextSize */ public void setMinTextSize(int minSize) { mHelper.setMinTextSize(TypedValue.COMPLEX_UNIT_SP, minSize); } /** * Set the minimum text size to a given unit and value. See TypedValue for the possible * dimension units. * * @param unit The desired dimension unit. * @param minSize The desired size in the given units. * * @attr ref me.grantland.R.styleable#AutofitTextView_minTextSize */ public void setMinTextSize(int unit, float minSize) { mHelper.setMinTextSize(unit, minSize); } /** * Returns the amount of precision used to calculate the correct text size to fit within its * bounds. */ public float getPrecision() { return mHelper.getPrecision(); } /** * Set the amount of precision used to calculate the correct text size to fit within its * bounds. Lower precision is more precise and takes more time. * * @param precision The amount of precision. */ public void setPrecision(float precision) { mHelper.setPrecision(precision); } @Override public void onTextSizeChange(float textSize, float oldTextSize) { // do nothing }}
MainActivity.java:
package com.example.demo;import android.app.Activity;import android.os.Bundle;import android.text.Editable;import android.text.TextWatcher;import android.widget.EditText;import android.widget.TextView;public class MainActivity extends Activity { private TextView mOutput, mAutofitOutput; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mOutput = (TextView)findViewById(R.id.output); mAutofitOutput = (TextView)findViewById(R.id.output_autofit); ((EditText)findViewById(R.id.input)).addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { // do nothing } @Override public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { mOutput.setText(charSequence); mAutofitOutput.setText(charSequence); } @Override public void afterTextChanged(Editable editable) { // do nothing } }); }}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?><ScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:autofit="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > <EditText android:id="@+id/input" android:layout_width="match_parent" android:layout_height="wrap_content" android:singleLine="true" android:hint="@string/input_hint" android:text="@string/example"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/label_normal" /> <TextView android:id="@+id/output" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/example" android:textSize="50sp" android:gravity="center" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/label_autofit" /> <com.example.demo.AutofitTextView android:id="@+id/output_autofit" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/example" android:textSize="50sp" android:gravity="center" android:singleLine="true" autofit:minTextSize="8sp" /> </LinearLayout></ScrollView>
源代码下载:
http://download.csdn.net/detail/su_tianbiao/8542471
1 0
- 安卓AutoFitTextView实例Dmeo分享自适应
- android-autofittextview自适应字体大小源码分析。
- 安卓自适应
- 安卓图片自适应
- 安卓新浪微博分享实例代码
- cocos2dx安卓自适应屏幕
- 安卓 seekbar 图片自适应
- 安卓开发分享
- 安卓分享功能
- 安卓分享
- 安卓QQ分享
- 安卓布局自适应px适配
- 安卓简单技术-Webview自适应手机屏幕
- 安卓开发时语言国际化自适应
- 安卓Handler实例
- 安卓ExpandableListView实例
- 安卓实例
- 安卓TXT阅读器分享
- 机器学习 Generative Learning Algorithm (B)
- iOS7 tabbar遮盖tableview的cell解决方法
- GTK - 如何去掉背后的黑色的控制台窗口?
- 【3.22】
- 不建立临时变量 交换两个数字
- 安卓AutoFitTextView实例Dmeo分享自适应
- [不定项选择题]
- Android bound service 详解三:使用Messenger
- 关于websocket的协议和应用
- Tomcat启动时报错java.io.EOFException的解决方法
- 作业3.23
- openwrt之一:在virtualbox中创建openwrt x86系统
- 多核多线程——使用GDB进行Debuge
- ubuntu cgroup使用