Android绘制动态折线图
所谓动态折线图,就是折线图能随着手指的滑动进行动态绘制,这里很定会产生动画效果。基于这个效果,这里使用SurfaceView进行制图。
实现步奏如下:
(1):这里新建一个绘图ChartView,继承SurfaceView并实现SurfaceHolder.Callback,Runnable接口,主要绘图工作在子线程中完成。
(2):现实SurfaceHolder.Callback接口的三个方法,并在surfaceCreated中开启子线程进行绘图。
(3):重写onTouchEvent方法,在Move事件中,根据手指的滑动距离计算偏移量,具体实现请看代码。
(4):这里的折线图的坐标值是随意添加的,可以在实际项目中根据需求自己添加。
(5):此例中有大量从集合中添加和删除元素,建议使用LinkedList来进行保存数据。
自定义ChartView:
publicclassChartViewextendsSurfaceViewimplementsSurfaceHolder.Callback,Runnable { privateContextmContext; privatePaintmPaint; privateResourcesres; privateDisplayMetricsdm; privateintcanvasHeight; privateintcanvasWidth; privateintbHeight=0; privateintbWidth; privatebooleanisMeasure=true; privatebooleancanScrollRight=true; privatebooleancanScrollLeft=true; //y轴最大值 privateintmaxValue; //y轴间隔值 privateintaverageValue; privateintmarginTop=20; privateintmarginBottom=80; //曲线上的总点数 privatePoint[]mPoints; //纵坐标值 privateLinkedListyRawData; //横坐标值 privateLinkedList xRawData; //根据间隔计算出的每个X的值 privateLinkedList xList=newLinkedList<>(); privateLinkedList xPreData=newLinkedList<>(); privateLinkedList yPreData=newLinkedList<>(); privateLinkedList xLastData=newLinkedList<>(); privateLinkedList yLastData=newLinkedList<>(); privateintspacingHeight; privateSurfaceHolderholder; privatebooleanisRunning=true; privateintlastX; privateintoffSet; privateRectmRect; privateintxAverageValue=0; publicChartView(Contextcontext) { this(context,null); } publicChartView(Contextcontext,AttributeSetattrs) { super(context,attrs); this.mContext=context; initView(); } privatevoidinitView() { this.res=mContext.getResources(); this.mPaint=newPaint(Paint.ANTI_ALIAS_FLAG); dm=newDisplayMetrics(); WindowManagerwm=(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 protectedvoidonSizeChanged(intw,inth,intoldW,intoldH) { if(isMeasure) { this.canvasHeight=getHeight(); this.canvasWidth=getWidth(); if(bHeight==0) { bHeight=canvasHeight-marginBottom; } bWidth=dip2px(30); xAverageValue=(canvasWidth-bWidth)/7; isMeasure=false; } } @Override publicvoidrun() { while(isRunning) { drawView(); try { Thread.sleep(100); } catch(InterruptedExceptione) { e.printStackTrace(); } } } privatevoiddrawView() { Canvascanvas=holder.lockCanvas(); canvas.drawColor(Color.WHITE); mPaint.setColor(res.getColor(R.color.color_f2f2f2)); drawAllXLine(canvas); mRect=newRect(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(inti=0;i 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; caseMotionEvent.ACTION_UP: break; } returntrue; } privatePoint[]getPoints() { Point[]points=newPoint[yRawData.size()]; for(inti=0;i yRawData,LinkedList xRawData,intmaxValue,intaverageValue) { this.maxValue=maxValue; this.averageValue=averageValue; this.mPoints=newPoint[yRawData.size()]; this.yRawData=yRawData; this.xRawData=xRawData; this.spacingHeight=maxValue/averageValue; } privateintdip2px(floatdpValue) { return(int)(dpValue*dm.density+0.5f); } }
MainActivity代码:
publicclassMainActivityextendsActivity { LinkedListyList; LinkedList xRawData; ChartViewchartView; @Override protectedvoidonCreate(BundlesavedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main_activity); chartView=(ChartView)findViewById(R.id.chartView); yList=newLinkedList<>(); 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=newLinkedList<>(); 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即可,这里不再贴出。可能写得有点仓促,如果不妥之处,请大家批评指正,谢谢!
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。