Android自定义View仿电影票分割线效果

前言:UI需要如下效果,开始想用.9图实现,但是UI说.9图可能会错位,emmmm。。。好吧,还是自己用代码写一个吧,反正代码也不多。


一、需求分析

这个效果可以理解为两个半圆+间断的线组成。

1、定义这个控件需要如下属性:

(1)两端半圆直径
(2)两端半圆颜色
(3)分割线颜色
(4)分割线长度(未定义,需要的可以自己加一下)
(5)分割线间隔长度 (未定义,需要的可以自己加一下)

2、自定义属性

<declare-styleable name="MyDividLine">
        <attr name="divid_line_color" format="color" />
        <attr name="port_shape_color" format="color" />
        <attr name="port_shape_height" format="dimension" />
    </declare-styleable>

3、定义属性变量

//分割线颜色
private int mDividLineColor;
//两端半圆颜色
private int mPortShapeColor;
//两端半圆高度(直径)
private int mPortShapeHeight;
//两端半圆半径
private int mPortShapeRadius;

4、为上面的属性定义默认值

//分割线默认颜色
private final int DIVIDLINE_DEFAULT_COLOR = 0xFFD9D9D9;
//两端半圆默认颜色
private final int PORTSHAPE_DEFAULT_COLOR = 0xFFF2F2F2;
//两端半圆默认高度(直径)
private final int PORTSHAPE_DEFAULT_HEIGHT = dp2px(15);

二、编码

一个自定义view的编码步骤可以大体分为:获取自定义属性 —— onMeasure() —— onDraw()。

1、获取自定义属性

在构造方法中我们获取想要的自定义属性,初始两端圆半径的值、画笔。

public MyDividLine(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyDividLine);
        mDividLineColor = ta.getColor(R.styleable.MyDividLine_divid_line_color, DIVIDLINE_DEFAULT_COLOR);
        mPortShapeColor = ta.getColor(R.styleable.MyDividLine_port_shape_color, PORTSHAPE_DEFAULT_COLOR);
        mPortShapeHeight = (int) ta.getDimension(R.styleable.MyDividLine_port_shape_height, PORTSHAPE_DEFAULT_HEIGHT);
        mPortShapeRadius = mPortShapeHeight / 2;
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStrokeWidth(dp2px(1));
        ta.recycle();
    }

2、重写onMeasure():

在测量高度时,不要忘记判断 MeasureSpec.UNSPECIFIED这个模式,否则在scrollview中会显示不出来。

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthVal = MeasureSpec.getSize(widthMeasureSpec);
        int heightVal = measureHeight(heightMeasureSpec);
        setMeasuredDimension(widthVal, heightVal);
    }
/**
     * 测量控件高度
     *
     * @param heightMeasureSpec
     * @return
     */
    private int measureHeight(int heightMeasureSpec) {
        int height = MeasureSpec.getSize(heightMeasureSpec);
        int mode = MeasureSpec.getMode(heightMeasureSpec);
        int result = 0;
        if (mode == MeasureSpec.EXACTLY) {
            result = height;
        } else if (mode == MeasureSpec.AT_MOST) {
            result = getPaddingTop() + getPaddingBottom() + mPortShapeHeight;
        }else if(mode == MeasureSpec.UNSPECIFIED){
            result = getPaddingTop() + getPaddingBottom() + mPortShapeHeight;
        }
        return result;
    }

3、重写onDraw()

这个环节需要对canvas、paint、path具有一定的基础,如果基础比较薄弱的同学可以参考启舰大神的博客Android自定义控件三部曲中的绘图篇

onDraw()里我们画的顺序是:左端半圆 —— 分割线  —— 右端半圆。
首先设置画笔参数:

canvas.save();
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(mPortShapeColor);

(1)画左端半圆

然后构建一个矩形,通过这个矩形画出半圆
 RectF rectF = new RectF(0, 0, mPortShapeHeight, mPortShapeHeight);
再然后我们就可以画左端的半圆了,不过在画之前我们需要将画布左移一个半径的距离。为什么要先移动一个半径的距离呢?我用一张图表示。

因为我们画半圆是通过canvas.drawArc()这个方法,这个方法通过我们上面定义的矩形内画一段圆弧(半圆也可以看成圆弧),虽然只画了一半圆,但是另一半的位置还是会留着。因为它是为我们预留了一个矩形的大小来让我们画圆弧。如果画布不移动的话,出来的效果就是下面的样子。

好了,搞清楚后就可以画半圆了

canvas.translate(-mPortShapeRadius, 0);
canvas.drawArc(rectF, 270, 180, true, mPaint);//从270度开始画,画180度圆弧。
canvas.restore();

这里canvas.restore()是将画布的位置复原。如果对canvas状态保存复原不懂的接着去上面启舰大神的博客里找介绍canvas图层的博文。

(2)画虚线

半圆搞定了,emmmm,,,虚线呢??小事小事,画虚线我们使用path来搞定,在drawPath前,我们先给paint设置一个
DashPathEffect。什么鬼,这是什么东西,莫慌莫慌,光看字面意思可以翻译为短跑路径效果,跑一下..停..跑一下..停.....是不是
恍然大悟,这不就是我们想要的虚线效果吗。

mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(mDividLineColor);
DashPathEffect effect = new DashPathEffect(new float[]{5, 5}, 0);
mPaint.setPathEffect(effect);
Path path = new Path();
path.moveTo(mPortShapeRadius + 3,getMeasuredHeight() / 2);
path.lineTo(getMeasuredWidth() - mPortShapeRadius - 3,getMeasuredHeight() / 2);
//虚线两端偏移3个像素
canvas.drawPath(path,mPaint);

(3)画右端半圆

到这里我们可以说是胜券在握了,你可以泡一杯茶放松放松了。。画右端就是把画左端反过来。注意不要忘了先右移画布哦~

 mPaint.setStyle(Paint.Style.FILL);
 mPaint.setColor(mPortShapeColor);
 rectF = new RectF(getMeasuredWidth() - mPortShapeHeight, 0, getMeasuredWidth(), mPortShapeHeight);
 canvas.translate(mPortShapeRadius, 0);
 canvas.drawArc(rectF, 90, 180, true, mPaint);//从90度开始画,画180度圆弧。

最终效果图:

总结:

一个简单的仿电影票分割线控件就完成了,没什么大问题,如果对自定义View有什么不懂的,接着去找万能的启舰大神。。把他的自定义View三部曲仔细的过一遍,再自定义view的时候,说完全没问题吧有点太狂了,中等没问题吧。好了,我去喝茶了。。







猜你喜欢

转载自blog.csdn.net/ever69/article/details/79213383