美文网首页
自定义View_使用canvas画一个斜角标

自定义View_使用canvas画一个斜角标

作者: BraveJoy | 来源:发表于2018-09-16 18:23 被阅读0次

    很长时间没写技术文章了,最近一直都很忙,好不容易周末休息趁有时间写写文章看看书,做一个记录总结。来看今天的效果,实现一个倾斜角标的展示效果,先来看下效果图。

    CustomTextView.png

    这个效果呢实现起来很简单,喊UI帮忙切个图往xml里一放就好,但是也存在一定的弊端,比如文字失真、屏幕适配等问题,所以还是代码实现比较好。一开始的想法是用TextView实现然后旋转45度就好了,但是会有问题,具体问题自己脑补一下啦~废话不多说,先放GitHub传送门:https://github.com/SuperKotlin/CustomTextView

    思路


    1.canvas旋转45°;
    2.获取文字的高度,然后根据文字高度计算背景色高度,赋值给Paint的宽度;
    3.计算出各坐标,使用drawLine画出背景色,再画出文字。
    

    说的再多,不如一张草图看得方便~

    示意图.png

    注:红色区域就代表一根线段(drawLine),这是我用了一支很粗的笔画出来的。

    实现过程

    1.先说一下,这里我是把view设置为宽高相等的正方形,这样比较容易理解和实现效果。那么就在onMeasure方法中把宽高设置成了一样的大小。

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        int size = width < height ? width : height;
        /**
         * 这里高度要和宽度一致,这样才能保证效果(不考虑测量模式)
         */
        setMeasuredDimension(size, size);
    }
    

    2.在onDraw方法中,获取canvas以view中心点旋转45度

    //这里宽高一致,所以我都写成了getWidth() ;
    canvas.rotate(45, getWidth() / 2, getWidth() / 2);
    

    3.获取文字高度,然后稍微处理一下赋值给画背景色块的画笔

    Paint.FontMetricsInt fontMetricsInt = mPaintText.getFontMetricsInt();
    float dy = (fontMetricsInt.bottom - fontMetricsInt.top) / 2 - fontMetricsInt.bottom;
    /**
     * 这里是设置文字的背景色块的高度,根据文字的高度
     */
    float mTextBackGroundHeight = dy * 2 * mOffset;
    mPaint.setStrokeWidth(mTextBackGroundHeight);
    

    4.OK,接下来我们就能用画笔在画布上作画了,从哪下手就需要精确的坐标点,我们先来画红色背景色部分,那么坐标(起点和终点的X、Y坐标)该怎么计算呢?

    坐标示意图.png

    由示意图可知:有了起点和终点坐标那么我们就可以调用drawLine(float startX, float startY, float stopX, float stopY, Paint paint)来画出图中红色的区域了,但是图中小x该如何求呢?勾股定理即可:
    首先我们可以求出view对角线的长度,再减去边长(getWidth),最后再除以2就得出x的长度了。代码如下:

    /**
     * 这里是求出背景块的中心点Y坐标
     */
    float startY = (getWidth() - mTextBackGroundHeight) / 2;
    /**
     * 这里x代表画布旋转以后,画笔需要延伸到旋转之前的那个点,具体请看博客介绍
     */
    float x = (float) ((Math.sqrt(2 * getWidth() * getWidth()) - getWidth()) / 2);
    canvas.drawLine(-x, startY, getWidth() + x, startY, mPaint);
    

    5.最后在画出文字,结束

    //画文字
    float mTetxWidth = mPaintText.measureText(mText, 0, mText.length());
    float dx = (getWidth() - mTetxWidth) / 2;
    canvas.drawText(mText, dx, startY + dy, mPaintText);
    

    完整代码:

    CustomTextView.java:

    public class CustomTextView extends View {
    
        private Context mContext;
        private Paint mPaintText;
        private Paint mPaint;
        private String mText = "";//需要绘制的文字
        private int mTextColor;
        private float mTextSize;
        private int mTextBgColor;
        private float mOffset = 2f;//背景色的高度偏移量控制值(文字高度的mOffset倍数)
    
        public void setmText(String mText) {
            this.mText = mText;
        }
    
        public void setmTextBgColor(int mTextBgColor) {
            this.mTextBgColor = mTextBgColor;
            mPaint.setColor(mTextBgColor);
        }
    
        public CustomTextView(Context context) {
            this(context, null);
        }
    
        public CustomTextView(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public CustomTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
    
            mContext = context;
    
            TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CustomTextView);
            mText = array.getString(R.styleable.CustomTextView_ct_title_name);
            mTextColor = array.getColor(R.styleable.CustomTextView_ct_title_color, Color.WHITE);
            mTextSize = array.getDimension(R.styleable.CustomTextView_ct_title_size, sp2px(context, 10));
            mTextBgColor = array.getColor(R.styleable.CustomTextView_ct_title_bd_color, Color.RED);
            array.recycle();
    
            mPaint = new Paint();
            mPaint.setStyle(Paint.Style.FILL);
            mPaint.setColor(mTextBgColor);
    
            mPaintText = new Paint();
            mPaintText.setAntiAlias(true);
            mPaintText.setColor(mTextColor);
            mPaintText.setTextSize(mTextSize);
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            int width = MeasureSpec.getSize(widthMeasureSpec);
            int height = MeasureSpec.getSize(heightMeasureSpec);
            int size = width < height ? width : height;
            /**
             * 这里高度要和宽度一致,这样才能保证效果(不考虑测量模式)
             */
            setMeasuredDimension(size, size);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            /**
             * 实现的原理,先把画布以中心点为准旋转45度,
             * 然后画文字,计算文字的高度,根据这个高度稍微再扩大一些做为背景条的高度,再画背景条(一条比较粗的直线)
             */
            canvas.rotate(45, getWidth() / 2, getWidth() / 2);
    
            if (!TextUtils.isEmpty(mText)) {
                Paint.FontMetricsInt fontMetricsInt = mPaintText.getFontMetricsInt();
                float dy = (fontMetricsInt.bottom - fontMetricsInt.top) / 2 - fontMetricsInt.bottom;
                /**
                 * 这里是设置文字的背景色块的高度,根据文字的高度
                 */
                float mTextBackGroundHeight = dy * 2 * mOffset;
                mPaint.setStrokeWidth(mTextBackGroundHeight);
    
                /**
                 * 这里是求出背景块的中心点Y坐标
                 */
                float startY = (getWidth() - mTextBackGroundHeight) / 2;
    
                /**
                 * 这里x代表画布旋转以后,画笔需要延伸到旋转之前的那个点,具体请看博客介绍
                 */
                float x = (float) ((Math.sqrt(2 * getWidth() * getWidth()) - getWidth()) / 2);
                canvas.drawLine(-x, startY, getWidth() + x, startY, mPaint);
    
                //画文字
                float mTetxWidth = mPaintText.measureText(mText, 0, mText.length());
                float dx = (getWidth() - mTetxWidth) / 2;
                canvas.drawText(mText, dx, startY + dy, mPaintText);
            }
        }
    
        public static int sp2px(Context context, float spValue) {
            final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
            return (int) (spValue * fontScale + 0.5f);
        }
    }
    

    GitHub传送门:源码

    相关文章

      网友评论

          本文标题:自定义View_使用canvas画一个斜角标

          本文链接:https://www.haomeiwen.com/subject/qzlfnftx.html