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;
//横坐标值
privateLinkedListxRawData;
//根据间隔计算出的每个X的值
privateLinkedListxList=newLinkedList<>();
privateLinkedListxPreData=newLinkedList<>();
privateLinkedListyPreData=newLinkedList<>();
privateLinkedListxLastData=newLinkedList<>();
privateLinkedListyLastData=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;i0)
{
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;iyRawData,LinkedListxRawData,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;
LinkedListxRawData;
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即可,这里不再贴出。可能写得有点仓促,如果不妥之处,请大家批评指正,谢谢!
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。