android 同根动画_详解android绘制动画效果的曲线图的实现

安卓绘制统计图可以用androidchart,也可以自己绘制,不像ios,android能找到的开源库在UI方面都很差,要做出吸引人地方还是需要自己绘制。

本文给出最常用的曲线图的绘制方法。

绘制曲线图首先需要画好横竖坐标轴建立坐标系,比如坐标系中的100距离应该在canvas中绘制多长,这个是需要计算的,其实坐标体系的建立是最复杂的,我看过很多第三方库的建立方法都不一样,有的要灵活一些,有的比较死板。至于绘制曲线要么是用Canvas.drawLine方法,要么是用Path.lineTo方法,看你自己的习惯。

为了做出一个外观良好的曲线图,我参考了两个开源代码,第一个的曲线图绘制限制较多,使用范围太窄,但是有数据变化时的动画效果。第二个的适用范围很广,他能根据数据集合自动计算横纵坐标的个数,在canvas上单元格的距离,只需输入坐标点就能自动建立坐标体系绘制曲线,但是没有动画效果。

先讲第一个LineView。

LineView的demo可以在这里下载,lineview其实只是github项目的一部分,我是将其提取出来了的,个人觉得他的其他部分没有参考价值。作者好像是个韩国人。

LineView的曲线绘制没有什么可取的部分,我想学习的是他实现动画效果的方法,设计的很好,但具体实现还需要改进,让动画更流畅。

Lineview的调用方法:

在xml中添加lineview控件

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:id="@+id/horizontalScrollView"

android:layout_alignParentRight="true"

android:layout_above="@+id/line_button">

android:layout_width="wrap_content"

android:layout_height="200dp"

class="com.example.widget.LineView"

android:id="@+id/line_view"/>

在activity代码中获取lineview对象:

finalLineView lineView = (LineView)findViewById(R.id.line_view);

添加横坐标:

int randomint = 9;

ArrayListtest =newArrayList();

for(inti=0;i

test.add(String.valueOf(i+1));

}

lineView.setBottomTextList(test);

允许绘制坐标点:

lineView.setDrawDotLine(true);

lineView.setShowPopup(LineView.SHOW_POPUPS_NONE);

ArrayList dataList =newArrayList();

intrandom = (int)(Math.random()*9+1);

for(inti=0;i

dataList.add((int)(Math.random()*random));

}

添加纵坐标的值:

ArrayList>dataLists =newArrayList>();

dataLists.add(dataList);

lineView.setDataList(dataLists);

从其用法中可以看出,lineview需要提前设定横坐标的范围,而且纵坐标的值必须和lineView.setBottomTextList(test)中添加的值一一对应(读lineview源码可以知道),使用起来很不方便,我觉得作者仅仅是做出了一条曲线而已,而不太关注是否有用。和很多曲线图的开源代码一样lineview允许一次绘制几根颜色不同的曲线。

只需在上面的代码中为dataLists再添加一个list成员就行。

Lineview的实现

Lineview是view的直接子类public class LineView extends View,因为其绘制曲线的方法本身没什么亮点就不讲了,简单提一下其measure方法。重点讲他是如何实现动画效果的。

其实我也不是很明白measure过程中有些代码,自己看吧:

@Override

protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec) {

intmViewWidth = measureWidth(widthMeasureSpec);

mViewHeight=measureHeight(heightMeasureSpec);

refreshAfterDataChanged();

setMeasuredDimension(mViewWidth,mViewHeight);

}

privateintmeasureWidth(intmeasureSpec){

inthorizontalGridNum = getHorizontalGridNum();

intpreferred =backgroundGridWidth*horizontalGridNum+sideLineLength*2;

returngetMeasurement(measureSpec, preferred);

}

privateintmeasureHeight(intmeasureSpec){

intpreferred = 0;

returngetMeasurement(measureSpec,preferred);

}

privateintgetMeasurement(intmeasureSpec,intpreferred){

intspecSize = MeasureSpec.getSize(measureSpec);

intmeasurement;

switch(MeasureSpec.getMode(measureSpec)){

caseMeasureSpec.EXACTLY:

measurement = specSize;

break;

caseMeasureSpec.AT_MOST:

measurement = Math.min(preferred,specSize);

break;

default:

measurement = preferred;

break;

}

returnmeasurement;

}

动画:

如何才能展现出一条曲线的变化过程呢,曲线在波动其实是纵坐标y值在上下波动,横坐标x值是没有变化的,但是不要紧这个办法即使x值变化也应该可以展示出动画来,只是可能动画有点乱乱的感觉。

一条曲线的动画其实是多个个点的值在不断变化引起的,因此传统的android动画满足不了这么细致的需求,得自己想办法。

假如我们有这样的9个点(1,2),(2,0),(3,0),(4,2),(5,1),(6,0),(7,1),(8,2),(9,1)则用lineview可以得到如下的曲线图:

我们先预设最初的点为(1,0), (2,0), (3,0), (4,0), (5,0), (6,0), (7,0), (8,0), (9,0)

然后每隔一段时间就让每个点的y+1,这样就能得到动画效果。

private Runnable animator = new Runnable() {

@Override

public void run() {

boolean needNewFrame = false;

for(ArrayList data :drawDotLists){

for(Dotdot : data){

dot.update();

if(!dot.isAtRest()){

needNewFrame = true;

}

}

}

if (needNewFrame) {

postDelayed(this, 10);

}

invalidate();

}

};

其中postDelayed(this, 10);表示每隔10毫秒执行一次值变化,同时刷新曲线图;dot.update();表示更新该点的值。有意思的是表示坐标的dot类,他不仅仅包含了坐标值,还有目标值:

classDot{

intx;

inty;

intdata;

inttargetX;

inttargetY;

intlinenumber;

intvelocity=MyUtils.dip2px(getContext(),2);

Dot(intx,inty,inttargetX,inttargetY,Integer data,intlinenumber){

this.x= x;

this.y= y;

this.linenumber=linenumber;

setTargetData(targetX,targetY,data,linenumber);

}

Point getPoint(){

returnnewPoint(x,y);

}

Dot setTargetData(inttargetX,inttargetY,Integer data,intlinenumber){

this.targetX=targetX;

this.targetY=targetY;

this.data=data;

this.linenumber=linenumber;

returnthis;

}

booleanisAtRest(){

return(x==targetX)&&(y==targetY);

}

voidupdate(){

x=updateSelf(x,targetX,velocity);

y=updateSelf(y,targetY,velocity);

}

privateintupdateSelf(intorigin,inttarget,intvelocity){

if(origin < target) {

origin += velocity;

}elseif(origin > target){

origin-= velocity;

}

if(Math.abs(target-origin)

origin = target;

}

returnorigin;

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值