当前位置: 移动技术网 > 移动技术>移动开发>Android > Android 自定义View实现芝麻分曲线图效果

Android 自定义View实现芝麻分曲线图效果

2019年07月24日  | 移动技术网移动技术  | 我要评论
1.简介 其实这个效果几天之前就写了,但是一直没有更新博客,本来想着把芝麻分雷达图也做好再发博客的,然后今天看到鸿洋的微信公众号有朋友发了芝麻分的雷达图,所以就算了,算是

1.简介

其实这个效果几天之前就写了,但是一直没有更新博客,本来想着把芝麻分雷达图也做好再发博客的,然后今天看到鸿洋的微信公众号有朋友发了芝麻分的雷达图,所以就算了,算是一个互补吧。平时文章也写的比较少,所以可能有点杂乱,有什么需要改进的地方欢迎给出建议,不胜感激。

效果图:

这里写图片描述

2.步骤:

初始化view的属性
初始化画笔
绘制代表最高分和最低分的两根虚线
绘制文字
绘制代表月份的属性
绘制芝麻分折线
绘制代表芝麻分的圆点
绘制选中分数的悬浮文字以及背景
处理点击事件

3.编码:

初始化view属性

/**
* 初始化布局配置
*
* @param context
* @param attrs
*/
private void initconfig(context context, attributeset attrs)
{
typedarray a = context.obtainstyledattributes(attrs,r.styleable.scoretrend);
maxscore=a.getint(r.styleable.scoretrend_max_score,700);
minscore=a.getint(r.styleable.scoretrend_min_score,650);
brokenlinecolor=a.getcolor(r.styleable.scoretrend_broken_line_color,brokenlinecolor);
a.recycle();
}

初始化画笔:

private void init()
{
brokenpath = new path();
brokenpaint = new paint();
brokenpaint.setantialias(true);
brokenpaint.setstyle(paint.style.stroke);
brokenpaint.setstrokewidth(diptopx(brokenlinewith));
brokenpaint.setstrokecap(paint.cap.round);
straightpaint = new paint();
straightpaint.setantialias(true);
straightpaint.setstyle(paint.style.stroke);
straightpaint.setstrokewidth(brokenlinewith);
straightpaint.setcolor((straightlinecolor));
straightpaint.setstrokecap(paint.cap.round);
dottedpaint = new paint();
dottedpaint.setantialias(true);
dottedpaint.setstyle(paint.style.stroke);
dottedpaint.setstrokewidth(brokenlinewith);
dottedpaint.setcolor((straightlinecolor));
dottedpaint.setstrokecap(paint.cap.round);
textpaint = new paint();
textpaint.setantialias(true);
textpaint.settextalign(paint.align.center);
textpaint.setstyle(paint.style.fill);
textpaint.setcolor((textnormalcolor));
textpaint.settextsize(diptopx(15));
}

绘制代表最高分和最低分虚线

//绘制虚线
private void drawdottedline(canvas canvas, float startx, float starty, float stopx, float stopy)
{
dottedpaint.setpatheffect(new dashpatheffect(new float[]{20, 10}, 4));
dottedpaint.setstrokewidth(1);
// 实例化路径
path mpath = new path();
mpath.reset();
// 定义路径的起点
mpath.moveto(startx, starty);
mpath.lineto(stopx, stopy);
canvas.drawpath(mpath, dottedpaint);
}

绘制文本

//绘制文本
private void drawtext(canvas canvas)
{
textpaint.settextsize(diptopx(12));
textpaint.setcolor(textnormalcolor);
canvas.drawtext(string.valueof(maxscore), viewwith * 0.1f - diptopx(10), viewheight * 0.15f + textsize * 0.25f, textpaint);
canvas.drawtext(string.valueof(minscore), viewwith * 0.1f - diptopx(10), viewheight * 0.4f + textsize * 0.25f, textpaint);
textpaint.setcolor(0xff7c7c7c);
float newwith = viewwith - (viewwith * 0.15f) * 2;//分隔线距离最左边和最右边的距离是0.15倍的viewwith
float coordinatex;//分隔线x坐标
textpaint.settextsize(diptopx(12));
textpaint.setstyle(paint.style.fill);
textpaint.setcolor(textnormalcolor);
textsize = (int) textpaint.gettextsize();
for(int i = 0; i < monthtext.length; i++)
{
coordinatex = newwith * ((float) (i) / (monthcount - 1)) + (viewwith * 0.15f);
if(i == selectmonth - 1)
{
textpaint.setstyle(paint.style.stroke);
textpaint.setcolor(brokenlinecolor);
rectf r2 = new rectf();
r2.left = coordinatex - textsize - diptopx(4);
r2.top = viewheight * 0.7f + diptopx(4) + textsize / 2;
r2.right = coordinatex + textsize + diptopx(4);
r2.bottom = viewheight * 0.7f + diptopx(4) + textsize + diptopx(8);
canvas.drawroundrect(r2, 10, 10, textpaint);
}
//绘制月份
canvas.drawtext(monthtext[i], coordinatex, viewheight * 0.7f + diptopx(4) + textsize + diptopx(5), textpaint);
textpaint.setcolor(textnormalcolor);
}
}

绘制代表月份的属性

//绘制月份的直线(包括刻度)
private void drawmonthline(canvas canvas)
{
straightpaint.setstrokewidth(diptopx(1));
canvas.drawline(0, viewheight * 0.7f, viewwith, viewheight * 0.7f, straightpaint);
float newwith = viewwith - (viewwith * 0.15f) * 2;//分隔线距离最左边和最右边的距离是0.15倍的viewwith
float coordinatex;//分隔线x坐标
for(int i = 0; i < monthcount; i++)
{
coordinatex = newwith * ((float) (i) / (monthcount - 1)) + (viewwith * 0.15f);
canvas.drawline(coordinatex, viewheight * 0.7f, coordinatex, viewheight * 0.7f + diptopx(4), straightpaint);
}
}

绘制芝麻分折线

//绘制折线
private void drawbrokenline(canvas canvas)
{
brokenpath.reset();
brokenpaint.setcolor(brokenlinecolor);
brokenpaint.setstyle(paint.style.stroke);
if(score.length == 0)
{
return;
}
log.v("scoretrend", "drawbrokenline: " + scorepoints.get(0));
brokenpath.moveto(scorepoints.get(0).x, scorepoints.get(0).y);
for(int i = 0; i < scorepoints.size(); i++)
{
brokenpath.lineto(scorepoints.get(i).x, scorepoints.get(i).y);
}
canvas.drawpath(brokenpath, brokenpaint);
}

绘制代表芝麻分的圆点

//绘制折线穿过的点
private void drawpoint(canvas canvas)
{
if(scorepoints == null)
{
return;
}
brokenpaint.setstrokewidth(diptopx(1));
for(int i = 0; i < scorepoints.size(); i++)
{
brokenpaint.setcolor(brokenlinecolor);
brokenpaint.setstyle(paint.style.stroke);
canvas.drawcircle(scorepoints.get(i).x, scorepoints.get(i).y, diptopx(3), brokenpaint);
brokenpaint.setcolor(color.white);
brokenpaint.setstyle(paint.style.fill);
if(i == selectmonth - 1)
{
brokenpaint.setcolor(0xffd0f3f2);
canvas.drawcircle(scorepoints.get(i).x, scorepoints.get(i).y, diptopx(8f), brokenpaint);
brokenpaint.setcolor(0xff81dddb);
canvas.drawcircle(scorepoints.get(i).x, scorepoints.get(i).y, diptopx(5f), brokenpaint);
//绘制浮动文本背景框
drawfloattextbackground(canvas, scorepoints.get(i).x, scorepoints.get(i).y - diptopx(8f));
textpaint.setcolor(0xffffffff);
//绘制浮动文字
canvas.drawtext(string.valueof(score[i]), scorepoints.get(i).x, scorepoints.get(i).y - diptopx(5f) - textsize, textpaint);
}
brokenpaint.setcolor(0xffffffff);
canvas.drawcircle(scorepoints.get(i).x, scorepoints.get(i).y, diptopx(1.5f), brokenpaint);
brokenpaint.setstyle(paint.style.stroke);
brokenpaint.setcolor(brokenlinecolor);
canvas.drawcircle(scorepoints.get(i).x, scorepoints.get(i).y, diptopx(2.5f), brokenpaint);
}
}

绘制选中分数的悬浮文字以及背景

//绘制显示浮动文字的背景
private void drawfloattextbackground(canvas canvas, int x, int y)
{
brokenpath.reset();
brokenpaint.setcolor(brokenlinecolor);
brokenpaint.setstyle(paint.style.fill);
//p1
point point = new point(x, y);
brokenpath.moveto(point.x, point.y);
//p2
point.x = point.x + diptopx(5);
point.y = point.y - diptopx(5);
brokenpath.lineto(point.x, point.y);
//p3
point.x = point.x + diptopx(12);
brokenpath.lineto(point.x, point.y);
//p4
point.y = point.y - diptopx(17);
brokenpath.lineto(point.x, point.y);
//p5
point.x = point.x - diptopx(34);
brokenpath.lineto(point.x, point.y);
//p6
point.y = point.y + diptopx(17);
brokenpath.lineto(point.x, point.y);
//p7
point.x = point.x + diptopx(12);
brokenpath.lineto(point.x, point.y);
//最后一个点连接到第一个点
brokenpath.lineto(x, y);
canvas.drawpath(brokenpath, brokenpaint);
}

处理点击事件

@override
public boolean ontouchevent(motionevent event)
{
this.getparent().requestdisallowintercepttouchevent(true);//一旦底层view收到touch的action后调用这个方法那么父层view就不会再调用onintercepttouchevent了,也无法截获以后的action
switch(event.getaction())
{
case motionevent.action_down:
break;
case motionevent.action_move:
break;
case motionevent.action_up:
onactionupevent(event);
this.getparent().requestdisallowintercepttouchevent(false);
break;
case motionevent.action_cancel:
this.getparent().requestdisallowintercepttouchevent(false);
break;
}
return true;
}
private void onactionupevent(motionevent event)
{
boolean isvalidtouch = validatetouch(event.getx(), event.gety());
if(isvalidtouch)
{
invalidate();
}
}
//是否是有效的触摸范围
private boolean validatetouch(float x, float y)
{
//曲线触摸区域
for(int i = 0; i < scorepoints.size(); i++)
{
// diptopx(8)乘以2为了适当增大触摸面积
if(x > (scorepoints.get(i).x - diptopx(8) * 2) && x < (scorepoints.get(i).x + diptopx(8) * 2))
{
if(y > (scorepoints.get(i).y - diptopx(8) * 2) && y < (scorepoints.get(i).y + diptopx(8) * 2))
{
selectmonth = i + 1;
return true;
}
}
}
//月份触摸区域
//计算每个月份x坐标的中心点
float monthtouchy = viewheight * 0.7f - diptopx(3);//减去diptopx(3)增大触摸面积
float newwith = viewwith - (viewwith * 0.15f) * 2;//分隔线距离最左边和最右边的距离是0.15倍的viewwith
float validtouchx[] = new float[monthtext.length];
for(int i = 0; i < monthtext.length; i++)
{
validtouchx[i] = newwith * ((float) (i) / (monthcount - 1)) + (viewwith * 0.15f);
}
if(y > monthtouchy)
{
for(int i = 0; i < validtouchx.length; i++)
{
log.v("scoretrend", "validatetouch: validtouchx:" + validtouchx[i]);
if(x < validtouchx[i] + diptopx(8) && x > validtouchx[i] - diptopx(8))
{
log.v("scoretrend", "validatetouch: " + (i + 1));
selectmonth = i + 1;
return true;
}
}
}
return false;
}

获取控件的宽高

@override
protected void onsizechanged(int w, int h, int oldw, int oldh)
{
super.onsizechanged(w, h, oldw, oldh);
viewwith = w;
viewheight = h;
initdata();
}

4.总结

还有一些比较不够完善的地方需要处理,比如说可以通过xml调节的属性太少了。平时写的东西还是太少了,希望以后多总结完善写作功底吧。需要的属性后面需要再完善吧

github地址:https://github.com/felixlee0527/zhimascorecurve

以上所述是小编给大家介绍的android 自定义view实现芝麻分曲线图效果,希望对大家有所帮助

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网