最近,在项目中需要实现一个柱状图,并在刷新柱状图的时候有一个动画(柱状图的柱子动态的画出来)。
实现柱状图常用的方法就是,通过继承View类,复写onDraw()方法,根据产品的需求在onDraw()方法里面画相应的矩形(drawRect方法)、文本(drawText方法)等。实现柱状图的难点在根据实际业务的需要计算每个柱子的位置。
下面详细介绍实现自定义View动画的方法,笔者在实现柱状图动画的时候试验了两种方法:
1.第一种方法,在绘制方法中,通过延时一个固定时间调用invalidate()方法,再继续绘制View实现动画效果,代码如下:
private int mIndex = 0;
private void drawBar(Canvas canvas) {
mPaint.setStyle(Paint.Style.FILL);
for (BarItemInfoBean tempBarPosition : mBarInfoList) {
PointF upperLeftPoint = tempBarPosition.getUpperLeftPoint();
PointF lowerRightPoint = tempBarPosition.getLowerRightPoint();
float left = upperLeftPoint.x;
float top = upperLeftPoint.y;
float right = lowerRightPoint.x;
float bottom = lowerRightPoint.y;
float delta = (lowerRightPoint.y - upperLeftPoint.y) / 10;
top = Math.max(lowerRightPoint.y - (mIndex + 1) * delta, upperLeftPoint.y);
canvas.drawRect(left, top, right, bottom, mPaint);
}
mIndex++;
if (mIndex < 10) { //通过10次延迟绘制实现动画效果
postDelayed(new Runnable() {
@Override
public void run() {
invalidate();
}
}, 30);
}
}
2.第二种方法,通过属性动画实现动画效果
首先自定义一个动画类,在类中创建一个动画属性的变量(mPhaseY ),而且必须为这个变量设置get 和 set函数,在创建ObjectAnimator对象时使用这个属性。
public class ChartAnimator {
private ValueAnimator.AnimatorUpdateListener mListener;
public ChartAnimator() {
}
public ChartAnimator(ValueAnimator.AnimatorUpdateListener listener) {
mListener = listener;
}
protected float mPhaseY = 1f;
public void animateY(int durationMillis) {
if (android.os.Build.VERSION.SDK_INT < 11)
return;
ObjectAnimator animatorY = ObjectAnimator.ofFloat(this, "phaseY", 0f, 1f);
animatorY.setDuration(durationMillis);
animatorY.addUpdateListener(mListener);
animatorY.start();
}
public float getPhaseY() {
return mPhaseY;
}
public void setPhaseY(float phase) {
mPhaseY = phase;
}
}
然后在自定义的柱状图里面实例化一个ChartAnimator对象,在onDraw()方法里面画柱子时,柱子的高度需要依赖ChartAnimator对象里动画属性(mPhaseY )的返回值。
private ChartAnimator mAnimator = new ChartAnimator();
private void drawBar(Canvas canvas) {
mPaint.setStyle(Paint.Style.FILL);
float phaseY = mAnimator.getPhaseY();
for (BarItemInfoBean tempBarPosition : mBarInfoList) {
PointF upperLeftPoint = tempBarPosition.getUpperLeftPoint();
PointF lowerRightPoint = tempBarPosition.getLowerRightPoint();
float left = upperLeftPoint.x;
float top = upperLeftPoint.y;
float right = lowerRightPoint.x;
float bottom = lowerRightPoint.y;
top = lowerRightPoint.y - (lowerRightPoint.y - upperLeftPoint.y) * phaseY;
canvas.drawRect(left, top, right, bottom, mPaint);
}
}
public void animateY(int durationMillis) {
mAnimator.animateY(durationMillis);
}
两种方法比较:
第一种方法,实现简单,在Android3.0以下的sdk上也可以实现,但是动画效果不如第二种方法好;
第二种方法,实现起来比较复杂,在Android3.0以上的sdk上才能使用,优点是可以很好的控制动画效果(例如动画持续时间、加速度、减速度等),而且方便扩展。