2018.10.08更新
添加支持gradle依赖,GitHub地址:https://github.com/kjt666/TicketDivideLine/tree/master。
控件新增三个属性:
1、分割线实线长度
2、分割线虚线长度(间隔长度)
3、分割线方向
UI效果图
一、需求分析
这个效果可以理解为两个半圆+间断的线组成。
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的时候,说完全没问题吧有点太狂了,中等没问题吧。好了,我去喝茶了。。