package dev.utils.app;

import android.content.res.ColorStateList;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.Html;
import android.text.InputFilter;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.method.HideReturnsTransformationMethod;
import android.text.method.PasswordTransformationMethod;
import android.text.method.TransformationMethod;
import android.util.TypedValue;
import android.view.View;
import android.widget.TextView;

import androidx.annotation.ColorInt;
import androidx.annotation.RequiresApi;

import java.util.ArrayList;
import java.util.List;

import dev.utils.LogPrintUtils;
import dev.utils.common.StringUtils;

/**
 * detail: TextView 工具类
 * @author Ttt
 * <pre>
 *     获取字体信息 Paint.FontMetrics
 *     @see <a href="https://blog.csdn.net/superbigcupid/article/details/47153139"/>
 *     @see <a href="http://www.cnblogs.com/tianzhijiexian/p/4297664.html"/>
 *     <p></p>
 *     TextView 设置行间距、行高, 以及字间距
 *     @see <a href="https://blog.csdn.net/shanshan_1117/article/details/79564271"/>
 *     <p></p>
 *     android:includeFontPadding
 *     @see <a href="https://blog.csdn.net/bdmh/article/details/78110557"/>
 *     <p></p>
 *     设置文字水平间距: {@link TextViewUtils#setLetterSpacing(View, float)}
 *     android:letterSpacing
 *     设置文字行间距 ( 行高 ): {@link TextViewUtils#setLineSpacing(View, float)}、{@link TextViewUtils#setLineSpacingAndMultiplier(View, float, float)}
 *     android:lineSpacingExtra
 *     android:lineSpacingMultiplier
 *     <p></p>
 *     setPaintFlags:
 *     Paint.ANTI_ALIAS_FLAG 抗锯齿标志
 *     Paint.FILTER_BITMAP_FLAG 使位图过滤的位掩码标志
 *     Paint.DITHER_FLAG 使位图进行有利的抖动的位掩码标志
 *     Paint.UNDERLINE_TEXT_FLAG 下划线
 *     Paint.STRIKE_THRU_TEXT_FLAG 中划线
 *     Paint.FAKE_BOLD_TEXT_FLAG 加粗
 *     Paint.LINEAR_TEXT_FLAG 使文本平滑线性扩展的油漆标志
 *     Paint.SUBPIXEL_TEXT_FLAG 使文本的亚像素定位的绘图标志
 *     Paint.EMBEDDED_BITMAP_TEXT_FLAG 绘制文本时允许使用位图字体的绘图标志
 * </pre>
 */
public final class TextViewUtils {

    private TextViewUtils() {
    }

    // 日志 TAG
    private static final String TAG = TextViewUtils.class.getSimpleName();

    // =================
    // = 获取 TextView =
    // =================

    /**
     * 获取 TextView
     * @param view {@link View}
     * @param <T>  泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T getTextView(final View view) {
        if (view != null) {
            try {
                return (T) view;
            } catch (Exception e) {
                LogPrintUtils.eTag(TAG, e, "getTextView");
            }
        }
        return null;
    }

    // ========
    // = Hint =
    // ========

    /**
     * 获取 Hint 文本
     * @param textView {@link TextView}
     * @param <T>      泛型
     * @return {@link TextView#getHint()}
     */
    public static <T extends TextView> String getHint(final T textView) {
        if (textView != null) {
            if (textView.getHint() != null) {
                return textView.getHint().toString();
            }
        }
        return null;
    }

    /**
     * 获取 Hint 文本
     * @param view {@link TextView}
     * @return {@link TextView#getHint()}
     */
    public static String getHint(final View view) {
        return getHint(getTextView(view));
    }

    /**
     * 获取多个 TextView Hint 文本
     * @param views View(TextView)[]
     * @return {@link List<String>} 多个 TextView Hint 文本
     */
    public static List<String> getHints(final View... views) {
        List<String> lists = new ArrayList<>();
        if (views != null) {
            for (View view : views) {
                String text = getHint(view);
                if (text != null) {
                    lists.add(text);
                }
            }
        }
        return lists;
    }

    /**
     * 获取多个 TextView Hint 文本
     * @param views TextView[]
     * @param <T>   泛型
     * @return {@link List<String>} 多个 TextView Hint 文本
     */
    public static <T extends TextView> List<String> getHints(final T... views) {
        List<String> lists = new ArrayList<>();
        if (views != null) {
            for (T view : views) {
                String text = getHint(view);
                if (text != null) {
                    lists.add(text);
                }
            }
        }
        return lists;
    }

    /**
     * 设置 Hint 文本
     * @param textView {@link TextView}
     * @param text     Hint text
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setHint(final T textView, final CharSequence text) {
        if (textView != null) {
            textView.setHint(text);
        }
        return textView;
    }

    /**
     * 设置 Hint 文本
     * @param view {@link TextView}
     * @param text Hint text
     * @return {@link View}
     */
    public static View setHint(final View view, final CharSequence text) {
        setHint(getTextView(view), text);
        return view;
    }

    /**
     * 获取 Hint 字体颜色
     * @param textView {@link TextView}
     * @param <T>      泛型
     * @return {@link ColorStateList}
     */
    public static <T extends TextView> ColorStateList getHintTextColors(final T textView) {
        if (textView != null) {
            return textView.getHintTextColors();
        }
        return null;
    }

    /**
     * 获取 Hint 字体颜色
     * @param view {@link TextView}
     * @return {@link ColorStateList}
     */
    public static ColorStateList getHintTextColors(final View view) {
        return getHintTextColors(getTextView(view));
    }

    /**
     * 设置 Hint 字体颜色
     * @param textView {@link TextView}
     * @param color    R.color.id
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setHintTextColor(final T textView, @ColorInt final int color) {
        if (textView != null) {
            textView.setHintTextColor(color);
        }
        return textView;
    }

    /**
     * 设置 Hint 字体颜色
     * @param view  {@link TextView}
     * @param color R.color.id
     * @return {@link View}
     */
    public static View setHintTextColor(final View view, @ColorInt final int color) {
        setHintTextColor(getTextView(view), color);
        return view;
    }

    /**
     * 设置 Hint 字体颜色
     * @param textView {@link TextView}
     * @param colors   {@link ColorStateList}
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setHintTextColor(final T textView, final ColorStateList colors) {
        if (textView != null) {
            textView.setHintTextColor(colors);
        }
        return textView;
    }

    /**
     * 设置 Hint 字体颜色
     * @param view   {@link TextView}
     * @param colors {@link ColorStateList}
     * @return {@link View}
     */
    public static View setHintTextColor(final View view, final ColorStateList colors) {
        setHintTextColor(getTextView(view), colors);
        return view;
    }

    /**
     * 设置多个 TextView Hint 字体颜色
     * @param color R.color.id
     * @param views View(TextView)[]
     * @return {@code true} success, {@code false} fail
     */
    public static boolean setHintTextColors(@ColorInt final int color, final View... views) {
        if (views != null) {
            for (View view : views) {
                setHintTextColor(view, color);
            }
            return true;
        }
        return false;
    }

    /**
     * 设置多个 TextView Hint 字体颜色
     * @param color R.color.id
     * @param views TextView[]
     * @param <T>   泛型
     * @return {@code true} success, {@code false} fail
     */
    public static <T extends TextView> boolean setHintTextColors(@ColorInt final int color, final T... views) {
        if (views != null) {
            for (T view : views) {
                setHintTextColor(view, color);
            }
            return true;
        }
        return false;
    }

    /**
     * 设置多个 TextView Hint 字体颜色
     * @param colors {@link ColorStateList}
     * @param views  View(TextView)[]
     * @return {@code true} success, {@code false} fail
     */
    public static boolean setHintTextColors(final ColorStateList colors, final View... views) {
        if (views != null) {
            for (View view : views) {
                setHintTextColor(view, colors);
            }
            return true;
        }
        return false;
    }

    /**
     * 设置多个 TextView Hint 字体颜色
     * @param colors {@link ColorStateList}
     * @param views  TextView[]
     * @param <T>    泛型
     * @return {@code true} success, {@code false} fail
     */
    public static <T extends TextView> boolean setHintTextColors(final ColorStateList colors, final T... views) {
        if (views != null) {
            for (T view : views) {
                setHintTextColor(view, colors);
            }
            return true;
        }
        return false;
    }

    // ========
    // = Text =
    // ========

    /**
     * 获取文本
     * @param textView {@link TextView}
     * @param <T>      泛型
     * @return {@link TextView#getText()}
     */
    public static <T extends TextView> String getText(final T textView) {
        if (textView != null) {
            return textView.getText().toString();
        }
        return null;
    }

    /**
     * 获取文本
     * @param view {@link TextView}
     * @return {@link TextView#getText()}
     */
    public static String getText(final View view) {
        return getText(getTextView(view));
    }

    /**
     * 获取多个 TextView 文本
     * @param views View(TextView)[]
     * @return {@link List<String>} 多个 TextView 文本
     */
    public static List<String> getTexts(final View... views) {
        List<String> lists = new ArrayList<>();
        if (views != null) {
            for (View view : views) {
                String text = getText(view);
                if (text != null) {
                    lists.add(text);
                }
            }
        }
        return lists;
    }

    /**
     * 获取多个 TextView 文本
     * @param views TextView[]
     * @param <T>   泛型
     * @return {@link List<String>} 多个 TextView 文本
     */
    public static <T extends TextView> List<String> getTexts(final T... views) {
        List<String> lists = new ArrayList<>();
        if (views != null) {
            for (T view : views) {
                String text = getText(view);
                if (text != null) {
                    lists.add(text);
                }
            }
        }
        return lists;
    }

    /**
     * 设置文本
     * @param textView {@link TextView}
     * @param text     TextView text
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setText(final T textView, final CharSequence text) {
        if (textView != null) {
            textView.setText(text);
        }
        return textView;
    }

    /**
     * 设置文本
     * @param view {@link TextView}
     * @param text TextView text
     * @return {@link View}
     */
    public static View setText(final View view, final CharSequence text) {
        setText(getTextView(view), text);
        return view;
    }

    /**
     * 设置多个 TextView 文本
     * @param text  TextView text
     * @param views View(TextView)[]
     * @return {@code true} success, {@code false} fail
     */
    public static boolean setTexts(final CharSequence text, final View... views) {
        if (views != null) {
            for (View view : views) {
                setText(view, text);
            }
            return true;
        }
        return false;
    }

    /**
     * 设置多个 TextView 文本
     * @param text  TextView text
     * @param views TextView[]
     * @param <T>   泛型
     * @return {@code true} success, {@code false} fail
     */
    public static <T extends TextView> boolean setTexts(final CharSequence text, final T... views) {
        if (views != null) {
            for (T view : views) {
                setText(view, text);
            }
            return true;
        }
        return false;
    }

    /**
     * 获取字体颜色
     * @param textView {@link TextView}
     * @param <T>      泛型
     * @return {@link ColorStateList}
     */
    public static <T extends TextView> ColorStateList getTextColors(final T textView) {
        if (textView != null) {
            return textView.getTextColors();
        }
        return null;
    }

    /**
     * 获取字体颜色
     * @param view {@link TextView}
     * @return {@link ColorStateList}
     */
    public static ColorStateList getTextColors(final View view) {
        return getTextColors(getTextView(view));
    }

    /**
     * 设置字体颜色
     * @param textView {@link TextView}
     * @param color    R.color.id
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setTextColor(final T textView, @ColorInt final int color) {
        if (textView != null) {
            textView.setTextColor(color);
        }
        return textView;
    }

    /**
     * 设置字体颜色
     * @param view  {@link TextView}
     * @param color R.color.id
     * @return {@link View}
     */
    public static View setTextColor(final View view, @ColorInt final int color) {
        setTextColor(getTextView(view), color);
        return view;
    }

    /**
     * 设置字体颜色
     * @param textView {@link TextView}
     * @param colors   {@link ColorStateList}
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setTextColor(final T textView, final ColorStateList colors) {
        if (textView != null) {
            textView.setTextColor(colors);
        }
        return textView;
    }

    /**
     * 设置字体颜色
     * @param view   {@link TextView}
     * @param colors {@link ColorStateList}
     * @return {@link View}
     */
    public static View setTextColor(final View view, final ColorStateList colors) {
        setTextColor(getTextView(view), colors);
        return view;
    }

    /**
     * 设置多个 TextView 字体颜色
     * @param color R.color.id
     * @param views View(TextView)[]
     * @return {@code true} success, {@code false} fail
     */
    public static boolean setTextColors(@ColorInt final int color, final View... views) {
        if (views != null) {
            for (View view : views) {
                setTextColor(view, color);
            }
            return true;
        }
        return false;
    }

    /**
     * 设置多个 TextView 字体颜色
     * @param color R.color.id
     * @param views TextView[]
     * @param <T>   泛型
     * @return {@code true} success, {@code false} fail
     */
    public static <T extends TextView> boolean setTextColors(@ColorInt final int color, final T... views) {
        if (views != null) {
            for (T view : views) {
                setTextColor(view, color);
            }
            return true;
        }
        return false;
    }

    /**
     * 设置多个 TextView 字体颜色
     * @param colors {@link ColorStateList}
     * @param views  View(TextView)[]
     * @return {@code true} success, {@code false} fail
     */
    public static boolean setTextColors(final ColorStateList colors, final View... views) {
        if (views != null) {
            for (View view : views) {
                setTextColor(view, colors);
            }
            return true;
        }
        return false;
    }

    /**
     * 设置多个 TextView 字体颜色
     * @param colors {@link ColorStateList}
     * @param views  TextView[]
     * @param <T>    泛型
     * @return {@code true} success, {@code false} fail
     */
    public static <T extends TextView> boolean setTextColors(final ColorStateList colors, final T... views) {
        if (views != null) {
            for (T view : views) {
                setTextColor(view, colors);
            }
            return true;
        }
        return false;
    }

    // ========
    // = Html =
    // ========

    /**
     * 设置 Html 内容
     * @param textView {@link TextView}
     * @param content  Html content
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setHtmlText(final T textView, final String content) {
        if (textView != null && content != null) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                textView.setText(Html.fromHtml(content, Html.FROM_HTML_MODE_LEGACY));
            } else {
                textView.setText(Html.fromHtml(content));
            }
        }
        return textView;
    }

    /**
     * 设置 Html 内容
     * @param view    {@link TextView}
     * @param content Html content
     * @return {@link View}
     */
    public static View setHtmlText(final View view, final String content) {
        setHtmlText(getTextView(view), content);
        return view;
    }

    /**
     * 设置多个 TextView Html 内容
     * @param content Html content
     * @param views   View(TextView)[]
     * @return {@code true} success, {@code false} fail
     */
    public static boolean setHtmlTexts(final String content, final View... views) {
        if (content != null && views != null) {
            for (View view : views) {
                setHtmlText(view, content);
            }
            return true;
        }
        return false;
    }

    /**
     * 设置多个 TextView Html 内容
     * @param content Html content
     * @param views   TextView[]
     * @param <T>     泛型
     * @return {@code true} success, {@code false} fail
     */
    public static <T extends TextView> boolean setHtmlTexts(final String content, final T... views) {
        if (content != null && views != null) {
            for (T view : views) {
                setHtmlText(view, content);
            }
            return true;
        }
        return false;
    }

    // ============
    // = 字体相关 =
    // ============

    /**
     * 获取字体
     * @param textView {@link TextView}
     * @param <T>      泛型
     * @return {@link Typeface}
     */
    public static <T extends TextView> Typeface getTypeface(final T textView) {
        if (textView != null) {
            return textView.getTypeface();
        }
        return null;
    }

    /**
     * 设置字体
     * @param textView {@link TextView}
     * @param typeface {@link Typeface} 字体样式
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setTypeface(final T textView, final Typeface typeface) {
        if (textView != null && typeface != null) {
            textView.setTypeface(typeface);
        }
        return textView;
    }

    /**
     * 设置字体
     * @param textView {@link TextView}
     * @param typeface {@link Typeface} 字体样式
     * @param style    样式
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setTypeface(final T textView, final Typeface typeface, final int style) {
        if (textView != null && typeface != null) {
            textView.setTypeface(typeface, style);
        }
        return textView;
    }

    /**
     * 设置字体
     * @param view     {@link TextView}
     * @param typeface {@link Typeface} 字体样式
     * @return {@link View}
     */
    public static View setTypeface(final View view, final Typeface typeface) {
        setTypeface(getTextView(view), typeface);
        return view;
    }

    /**
     * 设置字体
     * @param view     {@link TextView}
     * @param typeface {@link Typeface} 字体样式
     * @param style    样式
     * @return {@link View}
     */
    public static View setTypeface(final View view, final Typeface typeface, final int style) {
        setTypeface(getTextView(view), typeface, style);
        return view;
    }

    // =

    /**
     * 设置字体大小 - px 像素
     * @param textView {@link TextView}
     * @param size     字体大小
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setTextSizeByPx(final T textView, final float size) {
        return setTextSize(textView, TypedValue.COMPLEX_UNIT_PX, size);
    }

    /**
     * 设置字体大小 - sp 缩放像素
     * @param textView {@link TextView}
     * @param size     字体大小
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setTextSizeBySp(final T textView, final float size) {
        return setTextSize(textView, TypedValue.COMPLEX_UNIT_SP, size);
    }

    /**
     * 设置字体大小 - dp 与设备无关的像素
     * @param textView {@link TextView}
     * @param size     字体大小
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setTextSizeByDp(final T textView, final float size) {
        return setTextSize(textView, TypedValue.COMPLEX_UNIT_DIP, size);
    }

    /**
     * 设置字体大小 - inches 英寸
     * @param textView {@link TextView}
     * @param size     字体大小
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setTextSizeByIn(final T textView, final float size) {
        return setTextSize(textView, TypedValue.COMPLEX_UNIT_IN, size);
    }

    // =

    /**
     * 设置字体大小 - px 像素
     * @param view {@link TextView}
     * @param size 字体大小
     * @return {@link View}
     */
    public static View setTextSizeByPx(final View view, final float size) {
        setTextSize(getTextView(view), TypedValue.COMPLEX_UNIT_PX, size);
        return view;
    }

    /**
     * 设置字体大小 - sp 缩放像素
     * @param view {@link TextView}
     * @param size 字体大小
     * @return {@link View}
     */
    public static View setTextSizeBySp(final View view, final float size) {
        setTextSize(getTextView(view), TypedValue.COMPLEX_UNIT_SP, size);
        return view;
    }

    /**
     * 设置字体大小 - dp 与设备无关的像素
     * @param view {@link TextView}
     * @param size 字体大小
     * @return {@link View}
     */
    public static View setTextSizeByDp(final View view, final float size) {
        setTextSize(getTextView(view), TypedValue.COMPLEX_UNIT_DIP, size);
        return view;
    }

    /**
     * 设置字体大小 - inches 英寸
     * @param view {@link TextView}
     * @param size 字体大小
     * @return {@link View}
     */
    public static View setTextSizeByIn(final View view, final float size) {
        setTextSize(getTextView(view), TypedValue.COMPLEX_UNIT_IN, size);
        return view;
    }

    // =

    /**
     * 设置字体大小
     * @param textView {@link TextView}
     * @param unit     字体参数类型
     * @param size     字体大小
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setTextSize(final T textView, final int unit, final float size) {
        if (textView != null) {
            textView.setTextSize(unit, size);
        }
        return textView;
    }

    /**
     * 设置字体大小
     * @param view {@link TextView}
     * @param unit 字体参数类型
     * @param size 字体大小
     * @return {@link View}
     */
    public static View setTextSize(final View view, final int unit, final float size) {
        setTextSize(getTextView(view), unit, size);
        return view;
    }

    // =

    /**
     * 设置多个 TextView 字体大小
     * @param views View(TextView)[]
     * @param unit  参数类型
     * @param size  字体大小
     * @return {@code true} success, {@code false} fail
     */
    public static boolean setTextSizes(final View[] views, final int unit, final float size) {
        if (views != null) {
            for (View view : views) {
                setTextSize(view, unit, size);
            }
            return true;
        }
        return false;
    }

    /**
     * 设置多个 TextView 字体大小
     * @param views TextView[]
     * @param unit  参数类型
     * @param size  字体大小
     * @param <T>   泛型
     * @return {@code true} success, {@code false} fail
     */
    public static <T extends TextView> boolean setTextSizes(final T[] views, final int unit, final float size) {
        if (views != null) {
            for (T view : views) {
                setTextSize(view, unit, size);
            }
            return true;
        }
        return false;
    }

    // =

    /**
     * 获取 TextView 字体大小 - px
     * @param textView {@link TextView}
     * @param <T>      泛型
     * @return 字体大小 (px)
     */
    public static <T extends TextView> float getTextSize(final T textView) {
        if (textView != null) {
            return textView.getTextSize();
        }
        return -1f;
    }

    /**
     * 获取 TextView 字体大小 - px
     * @param view {@link TextView}
     * @return 字体大小 (px)
     */
    public static float getTextSize(final View view) {
        return getTextSize(getTextView(view));
    }

    // =

    /**
     * 清空 flags
     * @param textView {@link TextView}
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T clearFlags(final T textView) {
        if (textView != null) {
            textView.setPaintFlags(0);
        }
        return textView;
    }

    /**
     * 清空 flags
     * @param view {@link TextView}
     * @return {@link View}
     */
    public static View clearFlags(final View view) {
        clearFlags(getTextView(view));
        return view;
    }

    // =

    /**
     * 设置 TextView 是否加粗
     * @param textView {@link TextView}
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setBold(final T textView) {
        return setBold(textView, true);
    }

    /**
     * 设置 TextView 是否加粗
     * @param textView {@link TextView}
     * @param isBold   {@code true} yes, {@code false} no
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setBold(final T textView, final boolean isBold) {
        if (textView != null) {
            textView.setTypeface(Typeface.defaultFromStyle(isBold ? Typeface.BOLD : Typeface.NORMAL));
        }
        return textView;
    }

    /**
     * 设置 TextView 是否加粗
     * @param textView {@link TextView}
     * @param typeface {@link Typeface} 字体样式
     * @param isBold   {@code true} yes, {@code false} no
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setBold(final T textView, final Typeface typeface, final boolean isBold) {
        if (textView != null && typeface != null) {
            textView.setTypeface(typeface, isBold ? Typeface.BOLD : Typeface.NORMAL);
        }
        return textView;
    }

    /**
     * 设置 TextView 是否加粗
     * @param view {@link TextView}
     * @return {@link View}
     */
    public static View setBold(final View view) {
        setBold(getTextView(view), true);
        return view;
    }

    /**
     * 设置 TextView 是否加粗
     * @param view   {@link TextView}
     * @param isBold {@code true} yes, {@code false} no
     * @return {@link View}
     */
    public static View setBold(final View view, final boolean isBold) {
        setBold(getTextView(view), isBold);
        return view;
    }

    /**
     * 设置 TextView 是否加粗
     * @param view     {@link TextView}
     * @param typeface {@link Typeface} 字体样式
     * @param isBold   {@code true} yes, {@code false} no
     * @return {@link View}
     */
    public static View setBold(final View view, final Typeface typeface, final boolean isBold) {
        setBold(getTextView(view), typeface, isBold);
        return view;
    }

    // =

    /**
     * 设置下划线
     * @param textView {@link TextView}
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setUnderlineText(final T textView) {
        return setUnderlineText(textView, true);
    }

    /**
     * 设置下划线并加清晰
     * @param textView    {@link TextView}
     * @param isAntiAlias 是否消除锯齿
     * @param <T>         泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setUnderlineText(final T textView, final boolean isAntiAlias) {
        if (textView != null) {
            textView.setPaintFlags(textView.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
            if (isAntiAlias) {
                textView.setPaintFlags(textView.getPaintFlags() | Paint.ANTI_ALIAS_FLAG);
            }
        }
        return textView;
    }

    // =

    /**
     * 设置下划线
     * @param view {@link TextView}
     * @return {@link View}
     */
    public static View setUnderlineText(final View view) {
        setUnderlineText(getTextView(view), true);
        return view;
    }

    /**
     * 设置下划线并加清晰
     * @param view        {@link TextView}
     * @param isAntiAlias 是否消除锯齿
     * @return {@link View}
     */
    public static View setUnderlineText(final View view, final boolean isAntiAlias) {
        setUnderlineText(getTextView(view), isAntiAlias);
        return view;
    }

    // =

    /**
     * 设置中划线
     * @param textView {@link TextView}
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setStrikeThruText(final T textView) {
        return setStrikeThruText(textView, true);
    }

    /**
     * 设置中划线并加清晰
     * @param textView    {@link TextView}
     * @param isAntiAlias 是否消除锯齿
     * @param <T>         泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setStrikeThruText(final T textView, final boolean isAntiAlias) {
        if (textView != null) {
            textView.setPaintFlags(textView.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
            if (isAntiAlias) {
                textView.setPaintFlags(textView.getPaintFlags() | Paint.ANTI_ALIAS_FLAG);
            }
        }
        return textView;
    }

    // =

    /**
     * 设置中划线
     * @param view {@link TextView}
     * @return {@link View}
     */
    public static View setStrikeThruText(final View view) {
        setStrikeThruText(getTextView(view), true);
        return view;
    }

    /**
     * 设置中划线并加清晰
     * @param view        {@link TextView}
     * @param isAntiAlias 是否消除锯齿
     * @return {@link View}
     */
    public static View setStrikeThruText(final View view, final boolean isAntiAlias) {
        setStrikeThruText(getTextView(view), isAntiAlias);
        return view;
    }

    // =

    /**
     * 获取文字水平间距
     * @param textView {@link TextView}
     * @param <T>      泛型
     * @return 文字水平间距
     */
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public static <T extends TextView> float getLetterSpacing(final T textView) {
        if (textView != null) {
            return textView.getLetterSpacing();
        }
        return 0f;
    }

    /**
     * 设置文字水平间距
     * <pre>
     *     android:letterSpacing
     * </pre>
     * @param textView      {@link TextView}
     * @param letterSpacing 文字水平间距
     * @param <T>           泛型
     * @return {@link TextView}
     */
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public static <T extends TextView> T setLetterSpacing(final T textView, final float letterSpacing) {
        if (textView != null) {
            textView.setLetterSpacing(letterSpacing);
        }
        return textView;
    }

    /**
     * 设置文字水平间距
     * @param view          {@link TextView}
     * @param letterSpacing 文字水平间距
     * @return {@link View}
     */
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public static View setLetterSpacing(final View view, final float letterSpacing) {
        setLetterSpacing(getTextView(view), letterSpacing);
        return view;
    }

    // =

    /**
     * 获取文字行间距 ( 行高 )
     * @param textView {@link TextView}
     * @param <T>      泛型
     * @return 文字行间距 ( 行高 )
     */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
    public static <T extends TextView> float getLineSpacingExtra(final T textView) {
        if (textView != null) {
            return textView.getLineSpacingExtra();
        }
        return 0f;
    }

    /**
     * 获取文字行间距倍数
     * @param textView {@link TextView}
     * @param <T>      泛型
     * @return 文字行间距倍数
     */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
    public static <T extends TextView> float getLineSpacingMultiplier(final T textView) {
        if (textView != null) {
            return textView.getLineSpacingMultiplier();
        }
        return 0f;
    }

    /**
     * 设置文字行间距 ( 行高 )
     * @param textView    {@link TextView}
     * @param lineSpacing 文字行间距 ( 行高 ), android:lineSpacingExtra
     * @param <T>         泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setLineSpacing(final T textView, final float lineSpacing) {
        return setLineSpacingAndMultiplier(textView, lineSpacing, 1.0f);
    }

    /**
     * 设置文字行间距 ( 行高 )、行间距倍数
     * @param textView    {@link TextView}
     * @param lineSpacing 文字行间距 ( 行高 ), android:lineSpacingExtra
     * @param multiplier  行间距倍数, android:lineSpacingMultiplier
     * @param <T>         泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setLineSpacingAndMultiplier(final T textView, final float lineSpacing, final float multiplier) {
        if (textView != null) {
            textView.setLineSpacing(lineSpacing, multiplier);
        }
        return textView;
    }

    // =

    /**
     * 设置文字行间距 ( 行高 )
     * @param view        {@link TextView}
     * @param lineSpacing 文字行间距 ( 行高 ), android:lineSpacingExtra
     * @return {@link View}
     */
    public static View setLineSpacing(final View view, final float lineSpacing) {
        setLineSpacingAndMultiplier(getTextView(view), lineSpacing, 1.0f);
        return view;
    }

    /**
     * 设置文字行间距 ( 行高 )、行间距倍数
     * @param view        {@link TextView}
     * @param lineSpacing 文字行间距 ( 行高 ), android:lineSpacingExtra
     * @param multiplier  行间距倍数, android:lineSpacingMultiplier
     * @return {@link View}
     */
    public static View setLineSpacingAndMultiplier(final View view, final float lineSpacing, final float multiplier) {
        setLineSpacingAndMultiplier(getTextView(view), lineSpacing, multiplier);
        return view;
    }

    // =

    /**
     * 获取字体水平方向的缩放
     * @param textView {@link TextView}
     * @param <T>      泛型
     * @return 字体水平方向的缩放
     */
    public static <T extends TextView> float getTextScaleX(final T textView) {
        if (textView != null) {
            return textView.getTextScaleX();
        }
        return 0f;
    }

    /**
     * 设置字体水平方向的缩放
     * <pre>
     *     android:textScaleX
     * </pre>
     * @param textView {@link TextView}
     * @param size     缩放比例
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setTextScaleX(final T textView, final float size) {
        if (textView != null) {
            textView.setTextScaleX(size);
        }
        return textView;
    }

    /**
     * 设置字体水平方向的缩放
     * @param view {@link TextView}
     * @param size 缩放比例
     * @return {@link View}
     */
    public static View setTextScaleX(final View view, final float size) {
        setTextScaleX(getTextView(view), size);
        return view;
    }

    // =

    /**
     * 是否保留字体留白间隙区域
     * @param textView {@link TextView}
     * @param <T>      泛型
     * @return {@code true} yes, {@code false} no
     */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
    public static <T extends TextView> boolean getIncludeFontPadding(final T textView) {
        if (textView != null) {
            return textView.getIncludeFontPadding();
        }
        return false;
    }

    /**
     * 设置是否保留字体留白间隙区域
     * <pre>
     *     android:includeFontPadding
     * </pre>
     * @param textView   {@link TextView}
     * @param includepad 是否保留字体留白间隙区域
     * @param <T>        泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setIncludeFontPadding(final T textView, final boolean includepad) {
        if (textView != null) {
            textView.setIncludeFontPadding(includepad);
        }
        return textView;
    }

    /**
     * 设置是否保留字体留白间隙区域
     * @param view       {@link TextView}
     * @param includepad 是否保留字体留白间隙区域
     * @return {@link View}
     */
    public static View setIncludeFontPadding(final View view, final boolean includepad) {
        setIncludeFontPadding(getTextView(view), includepad);
        return view;
    }

    // =

    /**
     * 获取输入类型
     * @param textView {@link TextView}
     * @param <T>      泛型
     * @return 输入类型
     */
    public static <T extends TextView> int getInputType(final T textView) {
        if (textView != null) {
            return textView.getInputType();
        }
        return 0;
    }

    /**
     * 设置输入类型
     * @param textView {@link TextView}
     * @param type     类型
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setInputType(final T textView, final int type) {
        if (textView != null) {
            textView.setInputType(type);
        }
        return textView;
    }

    /**
     * 设置输入类型
     * @param view {@link TextView}
     * @param type 类型
     * @return {@link View}
     */
    public static View setInputType(final View view, final int type) {
        setInputType(getTextView(view), type);
        return view;
    }

    // =

    /**
     * 获取软键盘右下角按钮类型
     * @param textView {@link TextView}
     * @param <T>      泛型
     * @return 软键盘右下角按钮类型
     */
    public static <T extends TextView> int getImeOptions(final T textView) {
        if (textView != null) {
            return textView.getImeOptions();
        }
        return 0;
    }

    /**
     * 设置软键盘右下角按钮类型
     * @param textView   {@link TextView}
     * @param imeOptions 软键盘按钮类型
     * @param <T>        泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setImeOptions(final T textView, final int imeOptions) {
        if (textView != null) {
            textView.setImeOptions(imeOptions);
        }
        return textView;
    }

    /**
     * 设置软键盘右下角按钮类型
     * @param view       {@link TextView}
     * @param imeOptions 软键盘按钮类型
     * @return {@link View}
     */
    public static View setImeOptions(final View view, final int imeOptions) {
        setImeOptions(getTextView(view), imeOptions);
        return view;
    }

    // =

    /**
     * 设置行数
     * @param textView {@link TextView}
     * @param lines    行数
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setLines(final T textView, final int lines) {
        if (textView != null) {
            textView.setLines(lines);
        }
        return textView;
    }

    /**
     * 设置行数
     * @param view  {@link TextView}
     * @param lines 行数
     * @return {@link View}
     */
    public static View setLines(final View view, final int lines) {
        setLines(getTextView(view), lines);
        return view;
    }

    // =

    /**
     * 获取最大行数
     * @param textView {@link TextView}
     * @param <T>      泛型
     * @return 最大行数
     */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
    public static <T extends TextView> int getMaxLines(final T textView) {
        if (textView != null) {
            return textView.getMaxLines();
        }
        return 0;
    }

    /**
     * 设置最大行数
     * @param textView {@link TextView}
     * @param maxLines 最大行数
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setMaxLines(final T textView, final int maxLines) {
        if (textView != null) {
            textView.setMaxLines(maxLines);
        }
        return textView;
    }

    /**
     * 设置最大行数
     * @param view     {@link TextView}
     * @param maxLines 最大行数
     * @return {@link View}
     */
    public static View setMaxLines(final View view, final int maxLines) {
        setMaxLines(getTextView(view), maxLines);
        return view;
    }

    // =

    /**
     * 获取最小行数
     * @param textView {@link TextView}
     * @param <T>      泛型
     * @return 最小行数
     */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
    public static <T extends TextView> int getMinLines(final T textView) {
        if (textView != null) {
            return textView.getMinLines();
        }
        return 0;
    }

    /**
     * 设置最小行数
     * @param textView {@link TextView}
     * @param minLines 最小行数
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setMinLines(final T textView, final int minLines) {
        if (textView != null && minLines > 0) {
            textView.setMinLines(minLines);
        }
        return textView;
    }

    /**
     * 设置最小行数
     * @param view     {@link TextView}
     * @param minLines 最小行数
     * @return {@link View}
     */
    public static View setMinLines(final View view, final int minLines) {
        setMinLines(getTextView(view), minLines);
        return view;
    }

    // =

    /**
     * 获取最大字符宽度限制
     * @param textView {@link TextView}
     * @param <T>      泛型
     * @return 最大字符宽度限制
     */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
    public static <T extends TextView> int getMaxEms(final T textView) {
        if (textView != null) {
            return textView.getMaxEms();
        }
        return 0;
    }

    /**
     * 设置最大字符宽度限制
     * @param textView {@link TextView}
     * @param maxEms   最大字符
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setMaxEms(final T textView, final int maxEms) {
        if (textView != null && maxEms > 0) {
            textView.setMaxEms(maxEms);
        }
        return textView;
    }

    /**
     * 设置最大字符宽度限制
     * @param view   {@link TextView}
     * @param maxEms 最大字符
     * @return {@link View}
     */
    public static View setMaxEms(final View view, final int maxEms) {
        setMaxEms(getTextView(view), maxEms);
        return view;
    }

    // =

    /**
     * 获取最小字符宽度限制
     * @param textView {@link TextView}
     * @param <T>      泛型
     * @return 最小字符宽度限制
     */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
    public static <T extends TextView> int getMinEms(final T textView) {
        if (textView != null) {
            return textView.getMinEms();
        }
        return 0;
    }

    /**
     * 设置最小字符宽度限制
     * @param textView {@link TextView}
     * @param minEms   最小字符
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setMinEms(final T textView, final int minEms) {
        if (textView != null && minEms > 0) {
            textView.setMinEms(minEms);
        }
        return textView;
    }

    /**
     * 设置最小字符宽度限制
     * @param view   {@link TextView}
     * @param minEms 最小字符
     * @return {@link View}
     */
    public static View setMinEms(final View view, final int minEms) {
        setMinEms(getTextView(view), minEms);
        return view;
    }

    // =

    /**
     * 设置指定字符宽度
     * @param textView {@link TextView}
     * @param ems      字符
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setEms(final T textView, final int ems) {
        if (textView != null && ems > 0) {
            textView.setEms(ems);
        }
        return textView;
    }

    /**
     * 设置指定字符宽度
     * @param view {@link TextView}
     * @param ems  字符
     * @return {@link View}
     */
    public static View setEms(final View view, final int ems) {
        setEms(getTextView(view), ems);
        return view;
    }

    // =

    /**
     * 设置长度限制
     * @param textView  {@link TextView}
     * @param maxLength 长度限制
     * @param <T>       泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setMaxLength(final T textView, final int maxLength) {
        if (textView != null && maxLength > 0) {
            // 设置最大长度限制
            InputFilter[] filters = {new InputFilter.LengthFilter(maxLength)};
            textView.setFilters(filters);
        }
        return textView;
    }

    /**
     * 设置长度限制
     * @param view      {@link TextView}
     * @param maxLength 长度限制
     * @return {@link View}
     */
    public static View setMaxLength(final View view, final int maxLength) {
        setMaxLength(getTextView(view), maxLength);
        return view;
    }

    // =

    /**
     * 设置长度限制, 并且设置内容
     * @param textView  {@link TextView}
     * @param content   文本内容
     * @param maxLength 长度限制
     * @param <T>       泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setMaxLengthAndText(final T textView, final CharSequence content, final int maxLength) {
        setText(setMaxLength(textView, maxLength), content);
        return textView;
    }

    /**
     * 设置长度限制, 并且设置内容
     * @param view      {@link TextView}
     * @param content   文本内容
     * @param maxLength 长度限制
     * @return {@link View}
     */
    public static View setMaxLengthAndText(final View view, final CharSequence content, final int maxLength) {
        return setText(setMaxLength(view, maxLength), content);
    }

    // =

    /**
     * 获取 Ellipsize 效果
     * @param textView {@link TextView}
     * @param <T>      泛型
     * @return Ellipsize 效果
     */
    public static <T extends TextView> TextUtils.TruncateAt getEllipsize(final T textView) {
        if (textView != null) {
            return textView.getEllipsize();
        }
        return null;
    }

    /**
     * 设置 Ellipsize 效果
     * @param textView {@link TextView}
     * @param where    {@link TextUtils.TruncateAt}
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setEllipsize(final T textView, final TextUtils.TruncateAt where) {
        if (textView != null) {
            textView.setEllipsize(where);
        }
        return textView;
    }

    /**
     * 设置 Ellipsize 效果
     * @param view  {@link TextView}
     * @param where {@link TextUtils.TruncateAt}
     * @return {@link View}
     */
    public static View setEllipsize(final View view, final TextUtils.TruncateAt where) {
        setEllipsize(getTextView(view), where);
        return view;
    }

    // =

    /**
     * 获取自动识别文本类型
     * @param textView {@link TextView}
     * @param <T>      泛型
     * @return 自动识别文本类型
     */
    public static <T extends TextView> int getAutoLinkMask(final T textView) {
        if (textView != null) {
            return textView.getAutoLinkMask();
        }
        return 0;
    }

    /**
     * 设置自动识别文本链接
     * @param textView {@link TextView}
     * @param mask     {@link android.text.util.Linkify}
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setAutoLinkMask(final T textView, final int mask) {
        if (textView != null) {
            textView.setAutoLinkMask(mask);
        }
        return textView;
    }

    /**
     * 设置自动识别文本链接
     * @param view {@link TextView}
     * @param mask {@link android.text.util.Linkify}
     * @return {@link View}
     */
    public static View setAutoLinkMask(final View view, final int mask) {
        setAutoLinkMask(getTextView(view), mask);
        return view;
    }

    // =

    /**
     * 设置文本全为大写
     * @param textView {@link TextView}
     * @param allCaps  是否全部大写
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setAllCaps(final T textView, final boolean allCaps) {
        if (textView != null) {
            textView.setAllCaps(allCaps);
        }
        return textView;
    }

    /**
     * 设置文本全为大写
     * @param view    {@link TextView}
     * @param allCaps 是否全部大写
     * @return {@link View}
     */
    public static View setAllCaps(final View view, final boolean allCaps) {
        setAllCaps(getTextView(view), allCaps);
        return view;
    }

    // =

    /**
     * 获取 Gravity
     * @param textView {@link TextView}
     * @param <T>      泛型
     * @return {@link android.view.Gravity}
     */
    public static <T extends TextView> int getGravity(final T textView) {
        if (textView != null) {
            return textView.getGravity();
        }
        return 0;
    }

    /**
     * 设置 Gravity
     * @param textView {@link TextView}
     * @param gravity  {@link android.view.Gravity}
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setGravity(final T textView, final int gravity) {
        if (textView != null) {
            textView.setGravity(gravity);
        }
        return textView;
    }

    /**
     * 设置 Gravity
     * @param view    {@link TextView}
     * @param gravity {@link android.view.Gravity}
     * @return {@link View}
     */
    public static View setGravity(final View view, final int gravity) {
        setGravity(getTextView(view), gravity);
        return view;
    }

    // =

    /**
     * 获取文本视图显示转换
     * @param textView {@link TextView}
     * @param <T>      泛型
     * @return {@link TransformationMethod}
     */
    public static <T extends TextView> TransformationMethod getTransformationMethod(final T textView) {
        if (textView != null) {
            return textView.getTransformationMethod();
        }
        return null;
    }

    /**
     * 设置文本视图显示转换
     * @param textView {@link TextView}
     * @param method   {@link TransformationMethod}
     * @param <T>      泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setTransformationMethod(final T textView, final TransformationMethod method) {
        if (textView != null) {
            textView.setTransformationMethod(method);
        }
        return textView;
    }

    /**
     * 设置文本视图显示转换
     * @param view   {@link TextView}
     * @param method {@link TransformationMethod}
     * @return {@link View}
     */
    public static View setTransformationMethod(final View view, final TransformationMethod method) {
        setTransformationMethod(getTextView(view), method);
        return view;
    }

    // =

    /**
     * 设置密码文本视图显示转换
     * @param textView          {@link TextView}
     * @param isDisplayPassword 是否显示密码
     * @param <T>               泛型
     * @return {@link TextView}
     */
    public static <T extends TextView> T setTransformationMethod(final T textView, final boolean isDisplayPassword) {
        if (textView != null) {
            textView.setTransformationMethod(isDisplayPassword ?
                    HideReturnsTransformationMethod.getInstance() : PasswordTransformationMethod.getInstance());
        }
        return textView;
    }

    /**
     * 设置密码文本视图显示转换
     * @param view              {@link TextView}
     * @param isDisplayPassword 是否显示密码
     * @return {@link View}
     */
    public static View setTransformationMethod(final View view, final boolean isDisplayPassword) {
        setTransformationMethod(getTextView(view), isDisplayPassword);
        return view;
    }

    // =

    /**
     * 获取 TextView Paint
     * @param view {@link TextView}
     * @param <T>  泛型
     * @return {@link Paint}
     */
    public static <T extends TextView> Paint getPaint(final View view) {
        return getPaint(getTextView(view));
    }

    /**
     * 获取 TextView Paint
     * @param textView {@link TextView}
     * @param <T>      泛型
     * @return {@link Paint}
     */
    public static <T extends TextView> Paint getPaint(final T textView) {
        if (textView != null) {
            return textView.getPaint();
        }
        return null;
    }

    /**
     * 获取字体高度
     * @param textView {@link TextView}
     * @param <T>      泛型
     * @return 字体高度
     */
    public static <T extends TextView> int getTextHeight(final T textView) {
        return getTextHeight(getPaint(textView));
    }

    /**
     * 获取字体高度
     * @param paint {@link TextView#getPaint()}
     * @return 字体高度
     */
    public static int getTextHeight(final Paint paint) {
        if (paint != null) {
            // 获取字体高度
            Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt();
            // 计算内容高度
            int textHeight = (int) Math.ceil((fontMetrics.descent - fontMetrics.ascent));
            // 返回字体高度
            return textHeight;
        }
        return -1;
    }

    // =

    /**
     * 获取字体顶部偏移高度
     * @param textView {@link TextView}
     * @param <T>      泛型
     * @return 字体顶部偏移高度
     */
    public static <T extends TextView> int getTextTopOffsetHeight(final T textView) {
        return getTextTopOffsetHeight(getPaint(textView));
    }

    /**
     * 获取字体顶部偏移高度
     * @param paint {@link TextView#getPaint()}
     * @return 字体顶部偏移高度
     */
    public static int getTextTopOffsetHeight(final Paint paint) {
        if (paint != null) {
            // 获取字体高度
            Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt();
            // 计算字体偏差 ( 顶部偏差 )
            int baseLine = (int) Math.ceil(Math.abs(fontMetrics.top) - Math.abs(fontMetrics.ascent));
            // 返回顶部偏差
            return baseLine;
        }
        return -1;
    }

    // =

    /**
     * 计算字体宽度
     * @param textView {@link TextView}
     * @param text     待测量文本
     * @param <T>      泛型
     * @return 字体宽度
     */
    public static <T extends TextView> float getTextWidth(final T textView, final String text) {
        return getTextWidth(getPaint(textView), text);
    }

    /**
     * 计算字体宽度
     * @param textView {@link TextView}
     * @param <T>      泛型
     * @return 字体宽度
     */
    public static <T extends TextView> float getTextWidth(final T textView) {
        return getTextWidth(getPaint(textView), getText(textView));
    }

    /**
     * 计算字体宽度
     * @param paint {@link TextView#getPaint()}
     * @param text  待测量文本
     * @return 字体宽度
     */
    public static float getTextWidth(final Paint paint, final String text) {
        if (paint != null && text != null) {
            return paint.measureText(text);
        }
        return -1f;
    }

    // =

    /**
     * 计算字体宽度
     * @param view  {@link TextView}
     * @param text  待测量文本
     * @param start 开始位置
     * @param end   结束位置
     * @return 字体宽度
     */
    public static float getTextWidth(final View view, final String text, final int start, final int end) {
        return getTextWidth(getPaint(view), text, start, end);
    }

    /**
     * 计算字体宽度
     * @param view  {@link TextView}
     * @param text  待测量文本
     * @param start 开始位置
     * @param end   结束位置
     * @return 字体宽度
     */
    public static float getTextWidth(final View view, final CharSequence text, final int start, final int end) {
        return getTextWidth(getPaint(view), text, start, end);
    }

    /**
     * 计算字体宽度
     * @param view  {@link TextView}
     * @param text  待测量文本
     * @param start 开始位置
     * @param end   结束位置
     * @return 字体宽度
     */
    public static float getTextWidth(final View view, final char[] text, final int start, final int end) {
        return getTextWidth(getPaint(view), text, start, end);
    }

    // =

    /**
     * 计算字体宽度
     * @param paint {@link TextView#getPaint()}
     * @param text  待测量文本
     * @param start 开始位置
     * @param end   结束位置
     * @return 字体宽度
     */
    public static float getTextWidth(final Paint paint, final String text, final int start, final int end) {
        if (paint != null && text != null) {
            try {
                return paint.measureText(text, start, end);
            } catch (Exception e) {
                LogPrintUtils.eTag(TAG, e, "getTextWidth");
            }
        }
        return -1f;
    }

    /**
     * 计算字体宽度
     * @param paint {@link TextView#getPaint()}
     * @param text  待测量文本
     * @param start 开始位置
     * @param end   结束位置
     * @return 字体宽度
     */
    public static float getTextWidth(final Paint paint, final CharSequence text, final int start, final int end) {
        if (paint != null && text != null) {
            try {
                return paint.measureText(text, start, end);
            } catch (Exception e) {
                LogPrintUtils.eTag(TAG, e, "getTextWidth");
            }
        }
        return -1f;
    }

    /**
     * 计算字体宽度
     * @param paint {@link TextView#getPaint()}
     * @param text  待测量文本
     * @param start 开始位置
     * @param end   结束位置
     * @return 字体宽度
     */
    public static float getTextWidth(final Paint paint, final char[] text, final int start, final int end) {
        if (paint != null && text != null) {
            try {
                return paint.measureText(text, start, end);
            } catch (Exception e) {
                LogPrintUtils.eTag(TAG, e, "getTextWidth");
            }
        }
        return -1f;
    }

    // =

    /**
     * 获取画布中间居中位置
     * @param targetRect {@link Rect} 目标坐标
     * @param paint      {@link TextView#getPaint()}
     * @return 画布 Y 轴居中位置
     */
    public static int getCenterRectY(final Rect targetRect, final Paint paint) {
        if (targetRect != null && paint != null) {
            // 获取字体高度
            Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt();
            // 获取底部 Y 轴居中位置
            return targetRect.top + (targetRect.bottom - targetRect.top) / 2 - (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.top;
            // canvas.drawText(testString, targetRect.centerX(), baseline, paint);
        }
        return -1;
    }

    /**
     * 通过需要的高度, 计算字体大小
     * @param height 需要的高度
     * @return 字体大小
     */
    public static float reckonTextSizeByHeight(final int height) {
        return reckonTextSizeByHeight(height, 40.0f);
    }

    /**
     * 通过需要的高度, 计算字体大小
     * @param height    需要的高度
     * @param startSize 字体开始预估大小
     * @return 字体大小
     */
    public static float reckonTextSizeByHeight(final int height, final float startSize) {
        if (height <= 0 || startSize <= 0) return 0f;
        Paint paint = new Paint();
        // 默认字体大小
        float textSize = startSize;
        // 计算内容高度
        int calcTextHeight;
        // 特殊处理 ( 防止死循环记录控制 )
        int state = 0; // 1 -=, 2 +=
        // 循环计算
        while (true) {
            // 设置画笔大小
            paint.setTextSize(textSize);
            // 获取字体高度
            Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt();
            // 计算内容高度
            calcTextHeight = (int) Math.ceil((fontMetrics.descent - fontMetrics.ascent));
            // 符合条件则直接返回
            if (calcTextHeight == height) {
                return textSize;
            } else if (calcTextHeight > height) { // 如果计算的字体高度大于
                textSize -= 0.5f;
                if (state == 2) {
                    if (calcTextHeight < height) {
                        return textSize;
                    }
                }
                state = 1;
            } else {
                textSize += 0.5f;
                if (state == 1) {
                    if (calcTextHeight < height) {
                        return textSize;
                    }
                }
                state = 2;
            }
        }
    }

    /**
     * 通过需要的宽度, 计算字体大小 ( 最接近该宽度的字体大小 )
     * @param width    需要的宽度
     * @param textView {@link TextView}
     * @return 字体大小
     */
    public static float reckonTextSizeByWidth(final int width, final TextView textView) {
        return reckonTextSizeByWidth(width, textView, TextViewUtils.getText(textView));
    }

    /**
     * 通过需要的宽度, 计算字体大小 ( 最接近该宽度的字体大小 )
     * @param width    需要的宽度
     * @param textView {@link TextView}
     * @param content  待计算内容
     * @return 字体大小
     */
    public static float reckonTextSizeByWidth(final int width, final TextView textView, final String content) {
        if (textView == null || content == null) return 0f;
        return reckonTextSizeByWidth(width, TextViewUtils.getPaint(textView),
                TextViewUtils.getTextSize(textView), content);
    }

    /**
     * 通过需要的宽度, 计算字体大小 ( 最接近该宽度的字体大小 )
     * @param width       需要的宽度
     * @param curTextSize 当前字体大小
     * @param content     待计算内容
     * @return 字体大小
     */
    public static float reckonTextSizeByWidth(final int width, final float curTextSize, final String content) {
        if (width <= 0 || curTextSize <= 0 || content == null) return 0f;
        return reckonTextSizeByWidth(width, new Paint(), curTextSize, content);
    }

    /**
     * 通过需要的宽度, 计算字体大小 ( 最接近该宽度的字体大小 )
     * @param width       需要的宽度
     * @param paint       {@link Paint}
     * @param curTextSize 当前字体大小
     * @param content     待计算内容
     * @return 字体大小
     */
    public static float reckonTextSizeByWidth(final int width, final Paint paint,
                                              final float curTextSize, final String content) {
        if (paint == null || width <= 0 || curTextSize <= 0 || content == null) return 0f;
        if (StringUtils.isEmpty(content)) return curTextSize;
        // 初始化内容画笔, 计算宽高
        TextPaint tvPaint = new TextPaint(paint);
        // 字体大小
        float textSize = curTextSize;
        // 字体内容宽度
        int calcTextWidth;
        // 特殊处理 ( 防止死循环记录控制 )
        int state = 0; // 1 -=, 2 +=
        // 循环计算
        while (true) {
            // 设置画笔大小
            tvPaint.setTextSize(textSize);
            // 获取字体内容宽度
            calcTextWidth = (int) tvPaint.measureText(content);
            // 符合条件则直接返回
            if (calcTextWidth == width) {
                return textSize;
            } else if (calcTextWidth > width) { // 如果计算的字体宽度大于
                textSize -= 0.5f;
                if (state == 2) {
                    if (calcTextWidth < width) {
                        return textSize;
                    }
                }
                state = 1;
            } else {
                textSize += 0.5f;
                if (state == 1) {
                    if (calcTextWidth < width) {
                        return textSize;
                    }
                }
                state = 2;
            }
        }
    }

    // =

    /**
     * 计算第几位超过宽度
     * @param textView {@link TextView}
     * @param text     待测量文本
     * @param width    指定的宽度
     * @param <T>      泛型
     * @return -1 表示没超过, 其他值表示对应的索引位置
     */
    public static <T extends TextView> int calcTextWidth(final T textView, final String text, final float width) {
        return calcTextWidth(getPaint(textView), text, width);
    }

    /**
     * 计算第几位超过宽度
     * @param textView {@link TextView}
     * @param width    指定的宽度
     * @param <T>      泛型
     * @return -1 表示没超过, 其他值表示对应的索引位置
     */
    public static <T extends TextView> int calcTextWidth(final T textView, final float width) {
        return calcTextWidth(getPaint(textView), getText(textView), width);
    }

    /**
     * 计算第几位超过宽度
     * @param paint {@link TextView#getPaint()}
     * @param text  文本内容
     * @param width 指定的宽度
     * @return -1 表示没超过, 其他值表示对应的索引位置
     */
    public static int calcTextWidth(final Paint paint, final String text, final float width) {
        if (paint != null && text != null && width > 0) {
            // 全部文本宽度
            float allTextWidth = getTextWidth(paint, text);
            // 判断是否超过
            if (allTextWidth <= width) return -1; // 表示没超过
            // 获取数据长度
            int length = text.length();
            // 超过长度且只有一个数据, 那么只能是第一个就超过了
            if (length == 1) return 1;
            // 二分法寻找最佳位置
            int start = 0;
            int end = length;
            int mid = 0;
            // 判断是否大于位置
            while (start < end) {
                mid = (start + end) / 2;
                // 获取字体宽度
                float textWidth = getTextWidth(paint, text, 0, mid);
                // 如果相等直接返回
                if (textWidth == width) {
                    return mid;
                } else if (textWidth > width) {
                    end = mid - 1;
                } else {
                    start = mid + 1;
                }
            }
            // 计算最符合的位置
            for (int i = Math.min(Math.min(start, mid), end), len = length; i <= len; i++) {
                float textWidth = TextViewUtils.getTextWidth(paint, text, 0, i);
                if (textWidth >= width) return i;
            }
            return start;
        }
        return -1;
    }

    /**
     * 计算文本换行行数
     * @param textView {@link TextView}
     * @param text     待测量文本
     * @param width    指定的宽度
     * @param <T>      泛型
     * @return 行数
     */
    public static <T extends TextView> int calcTextLine(final T textView, final String text, final float width) {
        return calcTextLine(getPaint(textView), text, width);
    }

    /**
     * 计算文本行数
     * @param textView {@link TextView}
     * @param width    指定的宽度
     * @param <T>      泛型
     * @return 行数
     */
    public static <T extends TextView> int calcTextLine(final T textView, final float width) {
        return calcTextLine(getPaint(textView), getText(textView), width);
    }

    /**
     * 计算文本行数
     * @param paint {@link TextView#getPaint()}
     * @param text  文本内容
     * @param width 指定的宽度
     * @return 行数
     */
    public static int calcTextLine(final Paint paint, final String text, final float width) {
        if (paint != null && text != null && width > 0) {
            // 全部文本宽度
            float allTextWidth = getTextWidth(paint, text);
            // 判断是否超过
            if (allTextWidth <= width) return 1;
            int result = (int) (allTextWidth / width);
            return ((allTextWidth - width * result == 0f) ? result : result + 1);
        }
        return 0;
    }

    // =====================
    // = CompoundDrawables =
    // =====================

    /**
     * 获取 CompoundDrawables
     * @param textView {@link TextView}
     * @param <T>      泛型
     * @return Drawable[] { left, top, right, bottom }
     */
    public static <T extends TextView> Drawable[] getCompoundDrawables(final T textView) {
        if (textView != null) {
            return textView.getCompoundDrawables();
        }
        return new Drawable[]{null, null, null, null};
    }

    /**
     * 获取 CompoundDrawables Padding
     * @param textView {@link TextView}
     * @param <T>      泛型
     * @return CompoundDrawables Padding
     */
    public static <T extends TextView> int getCompoundDrawablePadding(final T textView) {
        if (textView != null) {
            return textView.getCompoundDrawablePadding();
        }
        return 0;
    }

    /**
     * 设置 CompoundDrawables Padding
     * @param textView {@link TextView}
     * @param padding  CompoundDrawables Padding
     * @param <T>      泛型
     * @return {@link View}
     */
    public static <T extends TextView> T setCompoundDrawablePadding(final T textView, final int padding) {
        if (textView != null) textView.setCompoundDrawablePadding(padding);
        return textView;
    }

    // ========================
    // = setCompoundDrawables =
    // ========================

    /**
     * 设置 Left CompoundDrawables
     * @param textView {@link TextView}
     * @param left     left Drawable
     * @param <T>      泛型
     * @return {@link View}
     */
    public static <T extends TextView> T setCompoundDrawablesByLeft(final T textView, final Drawable left) {
        return setCompoundDrawables(textView, left, null, null, null);
    }

    /**
     * 设置 Top CompoundDrawables
     * @param textView {@link TextView}
     * @param top      top Drawable
     * @param <T>      泛型
     * @return {@link View}
     */
    public static <T extends TextView> T setCompoundDrawablesByTop(final T textView, final Drawable top) {
        return setCompoundDrawables(textView, null, top, null, null);
    }

    /**
     * 设置 Right CompoundDrawables
     * @param textView {@link TextView}
     * @param right    right Drawable
     * @param <T>      泛型
     * @return {@link View}
     */
    public static <T extends TextView> T setCompoundDrawablesByRight(final T textView, final Drawable right) {
        return setCompoundDrawables(textView, null, null, right, null);
    }

    /**
     * 设置 Bottom CompoundDrawables
     * @param textView {@link TextView}
     * @param bottom   bottom Drawable
     * @param <T>      泛型
     * @return {@link View}
     */
    public static <T extends TextView> T setCompoundDrawablesByBottom(final T textView, final Drawable bottom) {
        return setCompoundDrawables(textView, null, null, null, bottom);
    }

    /**
     * 设置 CompoundDrawables
     * <pre>
     *     CompoundDrawable 的大小控制是通过 drawable.setBounds() 控制
     *     需要先设置 Drawable 的 setBounds
     *     {@link dev.utils.app.image.ImageUtils#setBounds}
     * </pre>
     * @param textView {@link TextView}
     * @param left     left Drawable
     * @param top      top Drawable
     * @param right    right Drawable
     * @param bottom   bottom Drawable
     * @param <T>      泛型
     * @return {@link View}
     */
    public static <T extends TextView> T setCompoundDrawables(final T textView,
                                                              final Drawable left, final Drawable top,
                                                              final Drawable right, final Drawable bottom) {
        if (textView != null) {
            try {
                textView.setCompoundDrawables(left, top, right, bottom);
            } catch (Exception e) {
                LogPrintUtils.eTag(TAG, e, "setCompoundDrawables");
            }
        }
        return textView;
    }

    // ===========================================
    // = setCompoundDrawablesWithIntrinsicBounds =
    // ===========================================

    /**
     * 设置 Left CompoundDrawables - 按照原有比例大小显示图片
     * @param textView {@link TextView}
     * @param left     left Drawable
     * @param <T>      泛型
     * @return {@link View}
     */
    public static <T extends TextView> T setCompoundDrawablesWithIntrinsicBoundsByLeft(final T textView, final Drawable left) {
        return setCompoundDrawablesWithIntrinsicBounds(textView, left, null, null, null);
    }

    /**
     * 设置 Top CompoundDrawables - 按照原有比例大小显示图片
     * @param textView {@link TextView}
     * @param top      top Drawable
     * @param <T>      泛型
     * @return {@link View}
     */
    public static <T extends TextView> T setCompoundDrawablesWithIntrinsicBoundsByTop(final T textView, final Drawable top) {
        return setCompoundDrawablesWithIntrinsicBounds(textView, null, top, null, null);
    }

    /**
     * 设置 Right CompoundDrawables - 按照原有比例大小显示图片
     * @param textView {@link TextView}
     * @param right    right Drawable
     * @param <T>      泛型
     * @return {@link View}
     */
    public static <T extends TextView> T setCompoundDrawablesWithIntrinsicBoundsByRight(final T textView, final Drawable right) {
        return setCompoundDrawablesWithIntrinsicBounds(textView, null, null, right, null);
    }

    /**
     * 设置 Bottom CompoundDrawables - 按照原有比例大小显示图片
     * @param textView {@link TextView}
     * @param bottom   bottom Drawable
     * @param <T>      泛型
     * @return {@link View}
     */
    public static <T extends TextView> T setCompoundDrawablesWithIntrinsicBoundsByBottom(final T textView, final Drawable bottom) {
        return setCompoundDrawablesWithIntrinsicBounds(textView, null, null, null, bottom);
    }

    /**
     * 设置 CompoundDrawables - 按照原有比例大小显示图片
     * @param textView {@link TextView}
     * @param left     left Drawable
     * @param top      top Drawable
     * @param right    right Drawable
     * @param bottom   bottom Drawable
     * @param <T>      泛型
     * @return {@link View}
     */
    public static <T extends TextView> T setCompoundDrawablesWithIntrinsicBounds(final T textView,
                                                                                 final Drawable left, final Drawable top,
                                                                                 final Drawable right, final Drawable bottom) {
        if (textView != null) {
            try {
                textView.setCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom);
            } catch (Exception e) {
                LogPrintUtils.eTag(TAG, e, "setCompoundDrawablesWithIntrinsicBounds");
            }
        }
        return textView;
    }
}