Android 自定义View实现芝麻分曲线图效果
程序员文章站
2024-02-29 12:57:22
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实现芝麻分曲线图效果,希望对大家有所帮助