package io.virtualapp.widgets; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.util.AttributeSet; import android.view.Gravity; import android.view.View; import io.virtualapp.R; public class LabelView extends View { private static final int DEFAULT_DEGREES = 45; private String mTextContent; private int mTextColor; private float mTextSize; private boolean mTextBold; private boolean mFillTriangle; private boolean mTextAllCaps; private int mBackgroundColor; private float mMinSize; private float mPadding; private int mGravity; private Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private Paint mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private Path mPath = new Path(); public LabelView(Context context) { this(context, null); } public LabelView(Context context, AttributeSet attrs) { super(context, attrs); obtainAttributes(context, attrs); mTextPaint.setTextAlign(Paint.Align.CENTER); } private void obtainAttributes(Context context, AttributeSet attrs) { TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.LabelView); mTextContent = ta.getString(R.styleable.LabelView_lv_text); mTextColor = ta.getColor(R.styleable.LabelView_lv_text_color, Color.parseColor("#ffffff")); mTextSize = ta.getDimension(R.styleable.LabelView_lv_text_size, sp2px(11)); mTextBold = ta.getBoolean(R.styleable.LabelView_lv_text_bold, true); mTextAllCaps = ta.getBoolean(R.styleable.LabelView_lv_text_all_caps, true); mFillTriangle = ta.getBoolean(R.styleable.LabelView_lv_fill_triangle, false); mBackgroundColor = ta.getColor(R.styleable.LabelView_lv_background_color, Color.parseColor("#FF4081")); mMinSize = ta.getDimension(R.styleable.LabelView_lv_min_size, mFillTriangle ? dp2px(35) : dp2px(50)); mPadding = ta.getDimension(R.styleable.LabelView_lv_padding, dp2px(3.5f)); mGravity = ta.getInt(R.styleable.LabelView_lv_gravity, Gravity.TOP | Gravity.LEFT); ta.recycle(); } public String getText() { return mTextContent; } public void setText(String text) { mTextContent = text; invalidate(); } public int getTextColor() { return mTextColor; } public void setTextColor(int textColor) { mTextColor = textColor; invalidate(); } public float getTextSize() { return mTextSize; } public void setTextSize(float textSize) { mTextSize = sp2px(textSize); invalidate(); } public boolean isTextBold() { return mTextBold; } public void setTextBold(boolean textBold) { mTextBold = textBold; invalidate(); } public boolean isFillTriangle() { return mFillTriangle; } public void setFillTriangle(boolean fillTriangle) { mFillTriangle = fillTriangle; invalidate(); } public boolean isTextAllCaps() { return mTextAllCaps; } public void setTextAllCaps(boolean textAllCaps) { mTextAllCaps = textAllCaps; invalidate(); } public int getBgColor() { return mBackgroundColor; } public void setBgColor(int backgroundColor) { mBackgroundColor = backgroundColor; invalidate(); } public float getMinSize() { return mMinSize; } public void setMinSize(float minSize) { mMinSize = dp2px(minSize); invalidate(); } public float getPadding() { return mPadding; } public void setPadding(float padding) { mPadding = dp2px(padding); invalidate(); } public int getGravity() { return mGravity; } /** * Gravity.TOP | Gravity.LEFT * Gravity.TOP | Gravity.RIGHT * Gravity.BOTTOM | Gravity.LEFT * Gravity.BOTTOM | Gravity.RIGHT */ public void setGravity(int gravity) { mGravity = gravity; } @Override protected void onDraw(Canvas canvas) { int size = getHeight(); mTextPaint.setColor(mTextColor); mTextPaint.setTextSize(mTextSize); mTextPaint.setFakeBoldText(mTextBold); mBackgroundPaint.setColor(mBackgroundColor); float textHeight = mTextPaint.descent() - mTextPaint.ascent(); if (mFillTriangle) { if (mGravity == (Gravity.TOP | Gravity.LEFT)) { mPath.reset(); mPath.moveTo(0, 0); mPath.lineTo(0, size); mPath.lineTo(size, 0); mPath.close(); canvas.drawPath(mPath, mBackgroundPaint); drawTextWhenFill(size, -DEFAULT_DEGREES, canvas, true); } else if (mGravity == (Gravity.TOP | Gravity.RIGHT)) { mPath.reset(); mPath.moveTo(size, 0); mPath.lineTo(0, 0); mPath.lineTo(size, size); mPath.close(); canvas.drawPath(mPath, mBackgroundPaint); drawTextWhenFill(size, DEFAULT_DEGREES, canvas, true); } else if (mGravity == (Gravity.BOTTOM | Gravity.LEFT)) { mPath.reset(); mPath.moveTo(0, size); mPath.lineTo(0, 0); mPath.lineTo(size, size); mPath.close(); canvas.drawPath(mPath, mBackgroundPaint); drawTextWhenFill(size, DEFAULT_DEGREES, canvas, false); } else if (mGravity == (Gravity.BOTTOM | Gravity.RIGHT)) { mPath.reset(); mPath.moveTo(size, size); mPath.lineTo(0, size); mPath.lineTo(size, 0); mPath.close(); canvas.drawPath(mPath, mBackgroundPaint); drawTextWhenFill(size, -DEFAULT_DEGREES, canvas, false); } } else { double delta = (textHeight + mPadding * 2) * Math.sqrt(2); if (mGravity == (Gravity.TOP | Gravity.LEFT)) { mPath.reset(); mPath.moveTo(0, (float) (size - delta)); mPath.lineTo(0, size); mPath.lineTo(size, 0); mPath.lineTo((float) (size - delta), 0); mPath.close(); canvas.drawPath(mPath, mBackgroundPaint); drawText(size, -DEFAULT_DEGREES, canvas, textHeight, true); } else if (mGravity == (Gravity.TOP | Gravity.RIGHT)) { mPath.reset(); mPath.moveTo(0, 0); mPath.lineTo((float) delta, 0); mPath.lineTo(size, (float) (size - delta)); mPath.lineTo(size, size); mPath.close(); canvas.drawPath(mPath, mBackgroundPaint); drawText(size, DEFAULT_DEGREES, canvas, textHeight, true); } else if (mGravity == (Gravity.BOTTOM | Gravity.LEFT)) { mPath.reset(); mPath.moveTo(0, 0); mPath.lineTo(0, (float) delta); mPath.lineTo((float) (size - delta), size); mPath.lineTo(size, size); mPath.close(); canvas.drawPath(mPath, mBackgroundPaint); drawText(size, DEFAULT_DEGREES, canvas, textHeight, false); } else if (mGravity == (Gravity.BOTTOM | Gravity.RIGHT)) { mPath.reset(); mPath.moveTo(0, size); mPath.lineTo((float) delta, size); mPath.lineTo(size, (float) delta); mPath.lineTo(size, 0); mPath.close(); canvas.drawPath(mPath, mBackgroundPaint); drawText(size, -DEFAULT_DEGREES, canvas, textHeight, false); } } } private void drawText(int size, float degrees, Canvas canvas, float textHeight, boolean isTop) { canvas.save(); canvas.rotate(degrees, size / 2f, size / 2f); float delta = isTop ? -(textHeight + mPadding * 2) / 2 : (textHeight + mPadding * 2) / 2; float textBaseY = size / 2 - (mTextPaint.descent() + mTextPaint.ascent()) / 2 + delta; canvas.drawText(mTextAllCaps ? mTextContent.toUpperCase() : mTextContent, getPaddingLeft() + (size - getPaddingLeft() - getPaddingRight()) / 2, textBaseY, mTextPaint); canvas.restore(); } private void drawTextWhenFill(int size, float degrees, Canvas canvas, boolean isTop) { canvas.save(); canvas.rotate(degrees, size / 2f, size / 2f); float delta = isTop ? -size / 4 : size / 4; float textBaseY = size / 2 - (mTextPaint.descent() + mTextPaint.ascent()) / 2 + delta; canvas.drawText(mTextAllCaps ? mTextContent.toUpperCase() : mTextContent, getPaddingLeft() + (size - getPaddingLeft() - getPaddingRight()) / 2, textBaseY, mTextPaint); canvas.restore(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int measuredWidth = measureWidth(widthMeasureSpec); setMeasuredDimension(measuredWidth, measuredWidth); } /** * 确定View宽度大小 */ private int measureWidth(int widthMeasureSpec) { int result; int specMode = MeasureSpec.getMode(widthMeasureSpec); int specSize = MeasureSpec.getSize(widthMeasureSpec); if (specMode == MeasureSpec.EXACTLY) {//大小确定直接使用 result = specSize; } else { int padding = getPaddingLeft() + getPaddingRight(); mTextPaint.setColor(mTextColor); mTextPaint.setTextSize(mTextSize); float textWidth = mTextPaint.measureText(mTextContent + ""); result = (int) ((padding + (int) textWidth) * Math.sqrt(2)); //如果父视图的测量要求为AT_MOST,即限定了一个最大值,则再从系统建议值和自己计算值中去一个较小值 if (specMode == MeasureSpec.AT_MOST) { result = Math.min(result, specSize); } result = Math.max((int) mMinSize, result); } return result; } protected int dp2px(float dp) { final float scale = getResources().getDisplayMetrics().density; return (int) (dp * scale + 0.5f); } protected int sp2px(float sp) { final float scale = getResources().getDisplayMetrics().scaledDensity; return (int) (sp * scale + 0.5f); } }