需求
1.数字为1位,显示圆形
2.数字为2位图形拉伸,左右各半圆
3.数字大于999,显示999+
4.自定义文字颜色,自定义背景色
效果(好吧,看起来挺low的)
本身并不复杂,不过作为一道计算题还是很不错的


1.自定义属性
<?xml version="1.0" encoding="utf-8"?><resources>    <!--计数TextView-->    <declare-styleable name="CountTextView">        <attr name="z_ctv_font_size" format="reference|dimension"/>        <attr name="z_ctv_num" format="integer"/>        <attr name="z_bg_color" format="reference|color"/>        <attr name="z_txt_color" format="reference|color"/>    </declare-styleable></resources>
2.分析
使用圆角矩形来画背景,Paint.getTextBounds来获取文字边界矩形
1).先绘制文字,将文字左顶点与屏幕左顶点重合
2).通过计算,画出一个数时的圆角矩形两个顶点(如下图)
3).通过数字位数来控制圆角矩形两顶点的X
4).通过画布平移让圆角矩形左顶点处于画布顶点
5).计算圆角矩形的宽高,设置View大小

public class CountTextView extends View {    private int mCtvFontSize = sp(100);    private int mCtvNum = 5;    private int mCtvBgColor = 0xffBFF3F7;    private int mCtvTxtColor = Color.WHITE;    private Paint mPaint;//主画笔    private Paint mTxtPaint;    private Rect mRect;    private String mStr;    private int mOffSet;    public CountTextView(Context context) {        this(context, null);    }    public CountTextView(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public CountTextView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CountTextView);        mCtvFontSize = (int) a.getDimension(R.styleable.CountTextView_z_ctv_font_size, mCtvFontSize);        mCtvNum = a.getInteger(R.styleable.CountTextView_z_ctv_num, mCtvNum);        mCtvTxtColor = a.getColor(R.styleable.CountTextView_z_txt_color, mCtvTxtColor);        mCtvBgColor = a.getColor(R.styleable.CountTextView_z_bg_color, mCtvBgColor);        a.recycle();        init();    }    private void init() {        //初始化主画笔        mTxtPaint = new Paint(Paint.ANTI_ALIAS_FLAG);        mTxtPaint.setColor(mCtvTxtColor);        mTxtPaint.setTextSize(mCtvFontSize);        mRect = new Rect();        mStr = mCtvNum + "";        if (mCtvNum >= 1000) {            mStr = "999+";        }        mTxtPaint.getTextBounds(mStr, 0, mStr.length(), mRect);        int AChartLen = mRect.width() / mStr.length();        mOffSet = (int) ((mStr.length() - 1) * AChartLen * 0.7f);        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);        mPaint.setColor(mCtvBgColor);        mPaint.setStrokeWidth(mRect.height());        mPaint.setStrokeCap(Paint.Cap.ROUND);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        //文字左侧距圆心的偏移        int offsetX = mRect.height() - mRect.width() / 2 + mOffSet;        setMeasuredDimension(2 * offsetX + mRect.width(), 2 * mRect.height());    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        canvas.save();        int offsetX = mRect.height() - mRect.width() / 2 + mOffSet;        canvas.translate(offsetX, mRect.height() / 2);        //圆角矩形左上点        int topX = mRect.width() / 2 - mRect.height();        int topY = -mRect.height() / 2;        //圆角矩形右下点        int bottomX = mRect.height() + mRect.width() / 2;        int bottomY = mRect.height() / 2 + mRect.height();                canvas.drawRoundRect(topX - mOffSet, topY, bottomX + mOffSet, bottomY,                mRect.height(), mRect.height(), mPaint);        canvas.drawText(mStr, 0, mRect.height(), mTxtPaint);        canvas.restore();    }    private int sp(float sp) {        return (int) TypedValue.applyDimension(                TypedValue.COMPLEX_UNIT_SP, sp, getResources().getDisplayMetrics());    }}
3.使用
<com.toly1994.c.view.CountTextView    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:layout_marginStart="8dp"    android:layout_marginTop="8dp"    app:layout_constraintStart_toStartOf="parent"    app:layout_constraintTop_toTopOf="parent"    app:z_ctv_font_size="40sp"    app:z_ctv_num="30"/>