资源下载 - 从此开始!

下载我_精品源码软件教程资源网

您的位置:主页 > 网络编程 > 正文

Android绘制动态折线图

2019-01-06 09:25 来源:互联网 编辑:admin

所谓动态折线图,就是折线图能随着手指的滑动进行动态绘制,这里很定会产生动画效果。基于这个效果,这里使用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即可,这里不再贴出。可能写得有点仓促,如果不妥之处,请大家批评指正,谢谢!

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

打赏一下,我们会为大家提供更多优质资源!

相关文章,95%的人会看!{有内幕、有真相...}

看过本文的人还看过

关闭

微信扫一扫

站长微信账号