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

Android绘制动态折线图

程序员文章站 2022-04-12 11:45:29
所谓动态折线图,就是折线图能随着手指的滑动进行动态绘制,这里很定会产生动画效果。基于这个效果,这里使用surfaceview进行制图。 实现步奏如下: (1): 这里新...

所谓动态折线图,就是折线图能随着手指的滑动进行动态绘制,这里很定会产生动画效果。基于这个效果,这里使用surfaceview进行制图。

实现步奏如下:

(1): 这里新建一个绘图chartview,继承surfaceview并实现surfaceholder.callback , runnable接口,主要绘图工作在子线程中完成。
(2):现实 surfaceholder.callback接口的三个方法,并在 surfacecreated中开启子线程进行绘图。
(3):重写ontouchevent方法,在move事件中,根据手指的滑动距离计算偏移量,具体实现请看代码。
(4): 这里的折线图的坐标值是随意添加的,可以在实际项目中根据需求自己添加。
(5):此例中有大量从集合中添加和删除元素,建议使用linkedlist来进行保存数据。

自定义chartview:

public class chartview extends surfaceview implements surfaceholder.callback , runnable
{
 private context mcontext;
 private paint mpaint;
 private resources res;
 private displaymetrics dm;

 private int canvasheight;
 private int canvaswidth;
 private int bheight = 0;
 private int bwidth;
 private boolean ismeasure = true;
 private boolean canscrollright = true;
 private boolean canscrollleft = true;

 //y轴最大值
 private int maxvalue;
 //y轴间隔值
 private int averagevalue;
 private int margintop = 20;
 private int marginbottom = 80;

 //曲线上的总点数
 private point[] mpoints;
 //纵坐标值
 private linkedlist<double> yrawdata;
 //横坐标值
 private linkedlist<string> xrawdata;
 //根据间隔计算出的每个x的值
 private linkedlist<integer> xlist = new linkedlist<>();
 private linkedlist<string> xpredata = new linkedlist<>();
 private linkedlist<double> ypredata = new linkedlist<>();

 private linkedlist<string> xlastdata = new linkedlist<>();
 private linkedlist<double> ylastdata = new linkedlist<>();
 private int spacingheight;

 private surfaceholder holder;
 private boolean isrunning = true;
 private int lastx;
 private int offset;
 private rect mrect;

 private int xaveragevalue = 0;


 public chartview(context context)
 {
  this(context , null);
 }

 public chartview(context context , attributeset attrs)
 {
  super(context, attrs);
  this.mcontext = context;
  initview();
 }

 private void initview()
 {
  this.res = mcontext.getresources();
  this.mpaint = new paint(paint.anti_alias_flag);
  dm = new displaymetrics();
  windowmanager wm = (windowmanager) mcontext.getsystemservice(context.window_service);
  wm.getdefaultdisplay().getmetrics(dm);

  xpredata.add("05-18");
  xpredata.add("05-17");
  xpredata.add("05-16");
  xpredata.add("05-15");
  xpredata.add("05-14");
  xpredata.add("05-13");

  ypredata.add(4.53);
  ypredata.add(3.45);
  ypredata.add(6.78);
  ypredata.add(5.21);
  ypredata.add(2.34);
  ypredata.add(6.32);

  xlastdata.add("05-26");
  xlastdata.add("05-27");
  xlastdata.add("05-28");
  xlastdata.add("05-29");
  xlastdata.add("05-30");
  xlastdata.add("05-31");

  ylastdata.add(2.35);
  ylastdata.add(5.43);
  ylastdata.add(6.23);
  ylastdata.add(7.33);
  ylastdata.add(3.45);
  ylastdata.add(2.45);

  holder = this.getholder();
  holder.addcallback(this);
 }

 @override
 protected void onsizechanged(int w , int h , int oldw , int oldh)
 {
  if (ismeasure)
  {
   this.canvasheight = getheight();
   this.canvaswidth = getwidth();
   if (bheight == 0)
   {
    bheight = canvasheight - marginbottom;
   }
   bwidth = dip2px(30);
   xaveragevalue = (canvaswidth - bwidth) / 7;
   ismeasure = false;
  }
 }


 @override
 public void run()
 {
  while (isrunning)
  {
   drawview();
   try
   {
    thread.sleep(100);
   }
   catch (interruptedexception e)
   {
    e.printstacktrace();
   }
  }
 }

 private void drawview()
 {
  canvas canvas = holder.lockcanvas();
  canvas.drawcolor(color.white);
  mpaint.setcolor(res.getcolor(r.color.color_f2f2f2));
  drawallxline(canvas);
  mrect = new rect(bwidth - 3, margintop - 5 ,
    bwidth + (canvaswidth - bwidth) / yrawdata.size() * (yrawdata.size() - 1) + 3, bheight + margintop + marginbottom);
  //锁定画图区域
  canvas.cliprect(mrect);
  drawallyline(canvas);

  mpoints = getpoints();

  mpaint.setcolor(res.getcolor(r.color.color_ff4631));
  mpaint.setstrokewidth(dip2px(2.5f));
  mpaint.setstyle(paint.style.stroke);
  drawline(canvas);

  mpaint.setstyle(paint.style.fill);
  for (int i = 0 ; i < mpoints.length ; i++)
  {
   canvas.drawcircle(mpoints[i].x , mpoints[i].y , 5 , mpaint);
  }

  holder.unlockcanvasandpost(canvas);
 }

 //绘制折线图
 private void drawline(canvas canvas)
 {
  point startp = null;
  point endp = null;
  for (int i = 0 ; i < mpoints.length - 1; i++)
  {
   startp = mpoints[i];
   endp = mpoints[i + 1];
   canvas.drawline(startp.x , startp.y , endp.x , endp.y , mpaint);
  }
 }

 //绘制所有的纵向分割线
 private void drawallyline(canvas canvas)
 {
  for (int i = 0 ; i < yrawdata.size() ; i++)
  {
   if (i == 0)
   {
    canvas.drawline(bwidth, margintop , bwidth, bheight + margintop , mpaint);
   }
   if (i == yrawdata.size() - 1)
   {
    canvas.drawline(bwidth + xaveragevalue * i, margintop , bwidth + xaveragevalue * i , bheight + margintop , mpaint);
   }
   xlist.add(bwidth + xaveragevalue * i);
   canvas.drawline(bwidth + xaveragevalue * i + offset, margintop , bwidth + xaveragevalue * i + offset , bheight + margintop , mpaint);
   drawtext(xrawdata.get(i) , bwidth + xaveragevalue * i - 30 + offset, bheight + dip2px(26) , canvas);

  }
 }

 //绘制所有的横向分割线
 private void drawallxline(canvas canvas)
 {
  for (int i = 0 ; i < spacingheight + 1 ; i++)
  {
   canvas.drawline(bwidth , bheight - (bheight / spacingheight) * i + margintop ,
     bwidth + xaveragevalue * (yrawdata.size() - 1) , bheight - (bheight / spacingheight) * i + margintop , mpaint);
   drawtext(string.valueof(averagevalue * i) , bwidth / 2 , bheight - (bheight / spacingheight) * i + margintop, canvas);
  }
 }

 //绘制坐标值
 private void drawtext(string text , int x , int y , canvas canvas)
 {
  paint p = new paint(paint.anti_alias_flag);
  p.settextsize(dip2px(12));
  p.setcolor(res.getcolor(r.color.color_999999));
  p.settextalign(paint.align.left);
  canvas.drawtext(text , x , y , p);
 }

 @override
 public void surfacecreated(surfaceholder surfaceholder)
 {
  new thread(this).start();
  log.d("ook" , "created");
 }

 @override
 public void surfacechanged(surfaceholder surfaceholder, int i, int i1, int i2)
 {
  log.d("ook" , "changed");
 }

 @override
 public void surfacedestroyed(surfaceholder surfaceholder)
 {
  isrunning = false;
  try
  {
   thread.sleep(500);
  }
  catch (interruptedexception e)
  {
   e.printstacktrace();
  }
 }

 @override
 public boolean ontouchevent(motionevent event)
 {
  int action = event.getaction();
  int rawx = (int) event.getx();
  switch (action)
  {
   case motionevent.action_down:
    lastx = rawx;
    break;
   case motionevent.action_move:
    int offsetx = rawx - lastx;
    if (xpredata.size() == 0 && offset > 0)
    {
     offset = 0;
     canscrollright = false;
    }
    if (xlastdata.size() == 0 && offset < 0)
    {
     offset = 0;
     canscrollleft = false;
    }
    offset = offset + offsetx;
    if (offset > xaveragevalue && canscrollright)
    {
     offset = offset % xaveragevalue;
     xrawdata.addfirst(xpredata.pollfirst());
     yrawdata.addfirst(ypredata.pollfirst());
     xlastdata.addfirst(xrawdata.removelast());
     ylastdata.addfirst(yrawdata.removelast());
     canscrollleft = true;
    }


    if (offset < -xaveragevalue && canscrollleft)
    {
     offset = offset % xaveragevalue;
     xrawdata.addlast(xlastdata.pollfirst());
     yrawdata.addlast(ylastdata.pollfirst());
     xpredata.addfirst(xrawdata.removefirst());
     ypredata.addfirst(yrawdata.removefirst());
     canscrollright = true;
    }
    lastx = rawx;
    break;
   case motionevent.action_up:
    break;
  }
  return true;
 }

 private point[] getpoints()
 {
  point[] points = new point[yrawdata.size()];
  for (int i = 0 ; i < yrawdata.size() ; i++)
  {
   int ph = bheight - (int)(bheight * (yrawdata.get(i) / maxvalue));

   points[i] = new point(xlist.get(i) + offset , ph + margintop);
  }
  return points;
 }

 public void setdata(linkedlist<double> yrawdata , linkedlist<string> xrawdata , int maxvalue , int averagevalue)
 {
  this.maxvalue = maxvalue;
  this.averagevalue = averagevalue;
  this.mpoints = new point[yrawdata.size()];
  this.yrawdata = yrawdata;
  this.xrawdata = xrawdata;
  this.spacingheight = maxvalue / averagevalue;
 }

 private int dip2px(float dpvalue)
 {
  return (int) (dpvalue * dm.density + 0.5f);
 }
}

mainactivity代码:

public class mainactivity extends activity
{
 linkedlist<double> ylist;
 linkedlist<string> xrawdata;
 chartview chartview;
 @override
 protected void oncreate(bundle savedinstancestate)
 {
  super.oncreate(savedinstancestate);
  setcontentview(r.layout.main_activity);
  chartview = (chartview) findviewbyid(r.id.chartview);

  ylist = new linkedlist<>();
  ylist.add(2.203);
  ylist.add(4.05);
  ylist.add(6.60);
  ylist.add(3.08);
  ylist.add(4.32);
  ylist.add(2.0);
  ylist.add(5.0);

  xrawdata = new linkedlist<>();
  xrawdata.add("05-19");
  xrawdata.add("05-20");
  xrawdata.add("05-21");
  xrawdata.add("05-22");
  xrawdata.add("05-23");
  xrawdata.add("05-24");
  xrawdata.add("05-25");

  chartview.setdata(ylist , xrawdata , 8 , 2);
 }
}

此例页面布局比较简单,就是在主页面布局中添加一个自定义的chartview即可,这里不再贴出。可能写得有点仓促,如果不妥之处,请大家批评指正,谢谢!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。