支持设置文本的TextFloatingActionButton

public class TextFloatingActionButton extends FloatingActionButton {    private String mText;    private TextDrawable mTextDrawable;    private int mTextColor;    private int mTextSize;    private int mTextStyle;    public TextFloatingActionButton(Context context) {        super(context);        initView(null);    }    public TextFloatingActionButton(Context context, AttributeSet attrs) {        super(context, attrs);        initView(attrs);    }    public TextFloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        initView(attrs);    }    private void initView(AttributeSet attrs) {        if (attrs == null) return;        TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.TextFloatingActionButton);        mText = typedArray.getString(R.styleable.TextFloatingActionButton_android_text);        mTextColor = typedArray.getColor(R.styleable.TextFloatingActionButton_android_textColor, Color.BLACK);        mTextSize = typedArray.getDimensionPixelSize(R.styleable.TextFloatingActionButton_android_textSize, ViewUtils.densityToPixel(12));        mTextStyle = typedArray.getInt(R.styleable.TextFloatingActionButton_android_textStyle, 0);        typedArray.recycle();        mTextDrawable = new TextDrawable(getContext());        mTextDrawable.setText(mText);        mTextDrawable.setTextAlign(Layout.Alignment.ALIGN_CENTER);        mTextDrawable.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize);        mTextDrawable.setTextStyle(mTextStyle);        mTextDrawable.setTextColor(mTextColor);        setImageDrawable(mTextDrawable);    }    public void setText(String text) {        mText = text;        mTextDrawable.setText(mText);    }    public void setTextColor(int textColor) {        mTextColor = textColor;        mTextDrawable.setTextColor(mTextColor);    }    public void setTextSize(int textSize) {        mTextSize = textSize;        mTextDrawable.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize);    }    public void setTextStyle(int textStyle) {        mTextStyle = textStyle;        mTextDrawable.setTextStyle(mTextStyle);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);    }}

其中用到的TextDrawable

/** * A Drawable object that draws text. * A TextDrawable accepts most of the same parameters that can be applied to * {@link android.widget.TextView} for displaying and formatting text. * 

* Optionally, a {@link Path} may be supplied on which to draw the text. *

* A TextDrawable has an intrinsic size equal to that required to draw all * the text it has been supplied, when possible. In cases where a {@link Path} * has been supplied, the caller must explicitly call * {@link #setBounds(Rect) setBounds()} to provide the Drawable * size based on the Path constraints. */public class TextDrawable extends Drawable { /* Platform XML constants for typeface */ private static final int SANS = 1; private static final int SERIF = 2; private static final int MONOSPACE = 3; /* Attribute lists to pull default values from the current theme */ private static final int[] themeAttributes = { android.R.attr.textAppearance }; private static final int[] appearanceAttributes = { android.R.attr.textSize, android.R.attr.typeface, android.R.attr.textStyle, android.R.attr.textColor }; private static final Rect DEFAULT_CONATINER_BOUNDS = new Rect(); /* Resources for scaling values to the given device */ private Resources mResources; /* Paint to hold most drawing primitives for the text */ private TextPaint mTextPaint; /* Layout is used to measure and draw the text */ private StaticLayout mTextLayout; /* Alignment of the text inside its bounds */ private Layout.Alignment mTextAlignment = Layout.Alignment.ALIGN_NORMAL; /* Optional path on which to draw the text */ private Path mTextPath; /* Stateful text color list */ private ColorStateList mTextColors; /* Container for the bounds to be reported to widgets */ private Rect mTextBounds; /* Text string to draw */ private CharSequence mText = ""; private Rect mContainerBounds = DEFAULT_CONATINER_BOUNDS; public TextDrawable(Context context) { super(); //Used to load and scale resource items mResources = context.getResources(); //Definition of this drawables size mTextBounds = new Rect(); //Paint to use for the text mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); mTextPaint.density = mResources.getDisplayMetrics().density; mTextPaint.setDither(true); int textSize = 15; ColorStateList textColor = null; int styleIndex = -1; int typefaceIndex = -1; //Set default parameters from the current theme TypedArray a = context.getTheme().obtainStyledAttributes(themeAttributes); int appearanceId = a.getResourceId(0, -1); a.recycle(); TypedArray ap = null; if (appearanceId != -1) { ap = context.obtainStyledAttributes(appearanceId, appearanceAttributes); } if (ap != null) { for (int i = 0; i < ap.getIndexCount(); i++) { int attr = ap.getIndex(i); switch (attr) { case 0: //Text Size textSize = a.getDimensionPixelSize(attr, textSize); break; case 1: //Typeface typefaceIndex = a.getInt(attr, typefaceIndex); break; case 2: //Text Style styleIndex = a.getInt(attr, styleIndex); break; case 3: //Text Color textColor = a.getColorStateList(attr); break; default: break; } } ap.recycle(); } setTextColor(textColor != null ? textColor : ColorStateList.valueOf(0xFF000000)); setRawTextSize(textSize); Typeface tf = null; switch (typefaceIndex) { case SANS: tf = Typeface.SANS_SERIF; break; case SERIF: tf = Typeface.SERIF; break; case MONOSPACE: tf = Typeface.MONOSPACE; break; } setTypeface(tf, styleIndex); } /** * Return the text currently being displayed */ public CharSequence getText() { return mText; } /** * Set the text that will be displayed * * @param text Text to display */ public void setText(CharSequence text) { if (text == null) text = ""; mText = text; measureContent(); } /** * Return the current text size, in pixels */ public float getTextSize() { return mTextPaint.getTextSize(); } /** * Set the text size. The value will be interpreted in "sp" units * * @param size Text size value, in sp */ public void setTextSize(float size) { setTextSize(TypedValue.COMPLEX_UNIT_SP, size); } /** * Set the text size, using the supplied complex units * * @param unit Units for the text size, such as dp or sp * @param size Text size value */ public void setTextSize(int unit, float size) { float dimension = TypedValue.applyDimension(unit, size, mResources.getDisplayMetrics()); setRawTextSize(dimension); } /* * Set the text size, in raw pixels */ private void setRawTextSize(float size) { if (size != mTextPaint.getTextSize()) { mTextPaint.setTextSize(size); measureContent(); } } /** * Return the horizontal stretch factor of the text */ public float getTextScaleX() { return mTextPaint.getTextScaleX(); } /** * Set the horizontal stretch factor of the text * * @param size Text scale factor */ public void setTextScaleX(float size) { if (size != mTextPaint.getTextScaleX()) { mTextPaint.setTextScaleX(size); measureContent(); } } /** * Return the current text alignment setting */ public Layout.Alignment getTextAlign() { return mTextAlignment; } /** * Set the text alignment. The alignment itself is based on the text layout direction. * For LTR text NORMAL is left aligned and OPPOSITE is right aligned. * For RTL text, those alignments are reversed. * * @param align Text alignment value. Should be set to one of: *

* {@link Layout.Alignment#ALIGN_NORMAL}, * {@link Layout.Alignment#ALIGN_NORMAL}, * {@link Layout.Alignment#ALIGN_OPPOSITE}. */ public void setTextAlign(Layout.Alignment align) { if (mTextAlignment != align) { mTextAlignment = align; measureContent(); } } /** * Sets the typeface and style in which the text should be displayed, * and turns on the fake bold and italic bits in the Paint if the * Typeface that you provided does not have all the bits in the * style that you specified. */ public void setTypeface(Typeface tf, int style) { if (style > 0) { if (tf == null) { tf = Typeface.defaultFromStyle(style); } else { tf = Typeface.create(tf, style); } setTypeface(tf); // now compute what (if any) algorithmic styling is needed int typefaceStyle = tf != null ? tf.getStyle() : 0; int need = style & ~typefaceStyle; mTextPaint.setFakeBoldText((need & Typeface.BOLD) != 0); mTextPaint.setTextSkewX((need & Typeface.ITALIC) != 0 ? -0.25f : 0); } else { mTextPaint.setFakeBoldText(false); mTextPaint.setTextSkewX(0); setTypeface(tf); } } /** * Return the current typeface and style that the Paint * using for display. */ public Typeface getTypeface() { return mTextPaint.getTypeface(); } /** * Sets the typeface and style in which the text should be displayed. * Note that not all Typeface families actually have bold and italic * variants, so you may need to use * {@link #setTypeface(Typeface, int)} to get the appearance * that you actually want. */ public void setTypeface(Typeface tf) { if (mTextPaint.getTypeface() != tf) { mTextPaint.setTypeface(tf); measureContent(); } } /** * Set a single text color for all states * * @param color Color value such as {@link Color#WHITE} or {@link Color#argb(int, int, int, int)} */ public void setTextColor(int color) { setTextColor(ColorStateList.valueOf(color)); } /** * Set the text color as a state list * * @param colorStateList ColorStateList of text colors, such as inflated from an R.color resource */ public void setTextColor(ColorStateList colorStateList) { mTextColors = colorStateList; updateTextColors(getState()); } /** * Optional Path object on which to draw the text. If this is set, * TextDrawable cannot properly measure the bounds this drawable will need. * You must call {@link #setBounds(int, int, int, int) setBounds()} before * applying this TextDrawable to any View. *

* Calling this method with null will remove any Path currently attached. */ public void setTextPath(Path path) { if (mTextPath != path) { mTextPath = path; measureContent(); } } /** * Internal method to take measurements of the current contents and apply * the correct bounds when possible. */ private void measureContent() { //If drawing to a path, we cannot measure intrinsic bounds //We must resly on setBounds being called externally if (mTextPath != null) { //Clear any previous measurement mTextLayout = null; mTextBounds.setEmpty(); } else { //Measure text bounds double desired = Math.ceil(Layout.getDesiredWidth(mText, mTextPaint)); mTextLayout = new StaticLayout(mText, mTextPaint, (int) desired, mTextAlignment, 1.0f, 0.0f, false); mTextBounds.set(0, 0, mTextLayout.getWidth(), mTextLayout.getHeight()); } //We may need to be redrawn invalidateSelf(); } /** * Internal method to apply the correct text color based on the drawable's state */ private boolean updateTextColors(int[] stateSet) { int newColor = mTextColors.getColorForState(stateSet, Color.WHITE); if (mTextPaint.getColor() != newColor) { mTextPaint.setColor(newColor); return true; } return false; } @Override protected void onBoundsChange(Rect bounds) { //Update the internal bounds in response to any external requests mTextBounds.set(bounds); } @Override public boolean isStateful() { /* * The drawable's ability to represent state is based on * the text color list set */ return mTextColors.isStateful(); } @Override protected boolean onStateChange(int[] state) { //Upon state changes, grab the correct text color return updateTextColors(state); } @Override public int getIntrinsicHeight() { //Return the vertical bounds measured, or -1 if none if (mTextBounds.isEmpty()) { return -1; } else { return (mTextBounds.bottom - mTextBounds.top); } } @Override public int getIntrinsicWidth() { //Return the horizontal bounds measured, or -1 if none if (mTextBounds.isEmpty()) { return -1; } else { return (mTextBounds.right - mTextBounds.left); } } public void setContainerBounds(Rect containerBounds) { if (containerBounds != null && !containerBounds.isEmpty()) { mContainerBounds = containerBounds; } } public void setContainerBounds(int left, int top, int right, int bottom) { Rect rect = new Rect(left, top, right, bottom); if (!rect.isEmpty()) { mContainerBounds = rect; } } @Override public void draw(Canvas canvas) { final Rect bounds = getBounds(); final int count = canvas.save(); if (mContainerBounds == DEFAULT_CONATINER_BOUNDS) { canvas.translate(bounds.left, bounds.top); } else { int measuredWidth = mContainerBounds.width(); int measuredHeight = mContainerBounds.height(); int textWidth = getTextBounds().width(); int textHeight = getTextBounds().height(); int left = -1 * Math.abs(measuredWidth / 2 - textWidth / 2); int top = -1 * Math.abs(measuredHeight / 2 - textHeight / 2); canvas.translate(left, top); } if (mTextPath == null) { //Allow the layout to draw the text mTextLayout.draw(canvas); } else { //Draw directly on the canvas using the supplied path canvas.drawTextOnPath(mText.toString(), mTextPath, 0, 0, mTextPaint); } canvas.restoreToCount(count); } public Rect getTextBounds() { return mTextBounds; } @Override public void setAlpha(int alpha) { if (mTextPaint.getAlpha() != alpha) { mTextPaint.setAlpha(alpha); } } @Override public int getOpacity() { return (mTextPaint.getAlpha() < 255) ? PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE; } @Override public void setColorFilter(ColorFilter cf) { if (mTextPaint.getColorFilter() != cf) { mTextPaint.setColorFilter(cf); } } public void setTextStyle(int style) { if (style > 0) { Typeface tf = getTypeface(); setTypeface(tf); // now compute what (if any) algorithmic styling is needed int typefaceStyle = tf != null ? tf.getStyle() : 0; int need = style & ~typefaceStyle; mTextPaint.setFakeBoldText((need & Typeface.BOLD) != 0); mTextPaint.setTextSkewX((need & Typeface.ITALIC) != 0 ? -0.25f : 0); } else { mTextPaint.setFakeBoldText(false); mTextPaint.setTextSkewX(0); } }}

自定义属性: 文件attrs.xml

                                        

注意:xml使用的时候,v7包28或以上必须:

    

其中app:maxImageSize="32dp"必须设置,否则会偏移,很丑

最终效果,见右下角“这是文本”按钮,就是最终效果拉:

更多相关文章

  1. Android(安卓)吸入动画效果详解(仿mac退出效果)
  2. android 实现图片加载效果
  3. android 程序全屏设置
  4. android屏幕亮度的调整
  5. Android:一些小总结
  6. android 设置全屏
  7. Android(安卓)自定义对话框(Dialog)设置显示大小方向
  8. Android实现动画持续旋转
  9. android ListView的分段显示、分页显示(附源码)

随机推荐

  1. 【工具类】Android获取平板物理唯一标识
  2. Android(安卓)自定义Drawable 实现圆角矩
  3. android8.0 反射Application 启动过程
  4. Aosp build mini_emulator_x86_64-userde
  5. Android(安卓)-- 跳转应用市场评分
  6. 固定定位做的登录页面案例
  7. vw+rem移动端响应式布局
  8. 20个常用正则表达式
  9. 漫画褶皱该怎么画?动漫衣服的褶皱画法
  10. iOS导航栏控制的一些总结