欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2024-02-29 12:57:22
1.简介 其实这个效果几天之前就写了,但是一直没有更新博客,本来想着把芝麻分雷达图也做好再发博客的,然后今天看到鸿洋的微信公众号有朋友发了芝麻分的雷达图,所以就算了,算是...

1.简介

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

效果图:

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

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实现芝麻分曲线图效果,希望对大家有所帮助