前段时间,发文求大牛帮忙解决这个问题,可能是问题比较简单吧,没大牛来回答,想想还是得靠自己,于是就继续查相关资料,最后经过一番激战,咳咳~奋斗!终于完成了,下面与大家分享一下。首先我们来看一下百度生活手记中的样式。
1、首先这是一个时间轴(当然只要长眼都能看出来…..)
2、其次这个时间轴不是传统意义上的时间轴而是贝塞尔曲线形式的时间轴
3、最后呢,这个时间轴是动态添加的(重点来了)
我在网上查质料,一般都是用path,虽然画曲线很方便,做动画也还行,但是如果你想获取贝塞尔曲线的点集我感觉就有点麻烦(个人技术有限),最后我发现了一个很好玩的东西ValueAnimator,没错就是它,由于这次主脚不是ValueAnimator, 我就不讲了等会遇到了,咱们再说(有兴趣的猿猴们可以看看自定义控件三部曲之动画篇(四)——ValueAnimator基本使用讲的很详细,我就不多说了)。
上来二话不说,先来一波咱的效果图(恩有点丑,没有做优化,效果是那样就行了,咱不过多的要求了)。
由于楼楼比较帅,不会用抓图,勉强看吧 具体效果用源码看一目了然,好了快中午了该上菜了。
画贝塞尔曲线
第一步获取控制点(本文用随机对象随机生成)
for (int i = 0; i < MAX_COUNT; i++) {
float fx = random.nextInt(w - REGION_WIDTH * 2) + REGION_WIDTH;
float fy = paintY + lasty;
mControlPoints.add(new PointF(fx, fy));
lasty = fy;
}MAX_COUNT:是贝塞尔曲线的阶数
paintY :每个控制点间隔多少距离
lasty:于上一个爱心间隔多少距离第二步用ValueAnimator动画来计算贝塞尔曲线的点集
public void initControlPonints() {
//通过贝塞尔曲线公式,自定义估值器
final BezierEvalutor evaluator = new BezierEvalutor(mControlPoints.size() - 1, 0);
//将估值器传入属性动画,不断的修改控件的坐标
ValueAnimator animator = ValueAnimator.ofObject(evaluator, mControlPoints.get(0), mControlPoints.get(mControlPoints.size() - 1));
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
PointF pointf = (PointF) animation.getAnimatedValue();
mBezierPoint = new PointF();
mBezierPoint.x = pointf.x;
mBezierPoint.y = pointf.y;
mBezierPoints.add(mBezierPoint);
if (ee == 0) {
PointF mBezierPoint2 = new PointF();
mBezierPoint2.x = mControlPoints.get(0).x;
mBezierPoint2.y = mControlPoints.get(0).y;
mlovePonits.add(mBezierPoint2);
} else if (ee % 30 == 0) {
// 这里是每次相隔30一个位置
mlovePonits.add(mBezierPoint);
}
ee++;
invalidate();
}
});
animator.setDuration(3000);
animator.start();
}
mControlPoints:控制点数组
evaluator:估值器
mBezierPoint :当前运动点坐标
mBezierPoints:贝塞尔曲线点集合
mBezierPoint2 :爱心点位置
- 第三步画爱心添加动画
for (int i = 0; i < mlovePonits.size(); i++) {
if (mBezierPoint.y == mlovePonits.get(i).y && mBezierPoint.x == mlovePonits.get(i).x) {
// canvas.drawCircle(mBezierPoint.x, mBezierPoint.y, 15, mlovePaint);
ImageView imageView = new ImageView(getContext());
firstDrawable = getResources().getDrawable(R.drawable.pic2);
imageView.setImageDrawable(firstDrawable);
//得到爱心图片的宽高
// dHeight = firstDrawable.getIntrinsicHeight();
// dWidth = firstDrawable.getIntrinsicWidth();
params = new LayoutParams(60, 60);
imageView.setLayoutParams(params);
imageView.setX(mBezierPoint.x - 30);
imageView.setY(mBezierPoint.y - 30);
addView(imageView);
set = getAnimator(imageView);//通过getAnimator得到整个爱心所有动画集合
set.start();
}
}
//构造3个属性动画
private AnimatorSet getAnimator(ImageView mImageView) {
// Log.e("aaa", "进来了");
//1,alpha动画;2,
ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(mImageView, "alpha", 1.0f, 0.3f);
alphaAnimator.setRepeatCount(0);
ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(mImageView, "scaleX", 0.2f, 1.0f);
scaleXAnimator.setRepeatCount(0);
ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(mImageView, "scaleY", 0.2f, 1.0f);
scaleYAnimator.setRepeatCount(0);
AnimatorSet mAnimatorSet = new AnimatorSet();
mAnimatorSet.setDuration(500);
//三个动画同时集合
mAnimatorSet.playTogether(alphaAnimator, scaleXAnimator, scaleYAnimator);
mAnimatorSet.setTarget(mImageView);
return mAnimatorSet;//返回一个整体爱心所有动画的集合
}
完了?啊哈?不是吧?怎么可能?
好吧肯定不可能啊 估值器在哪呢?那才是wighthead啊
最后,注意了啊 重点来了
- 估值器
/**
* @author mikyou
* 自定义估值器
*/
public class BezierEvalutor implements TypeEvaluator<PointF> {
int i;
int j;
public BezierEvalutor(int i, int j) {
super();
this.i = i;
this.j = j;
}
@Override
public PointF evaluate(float t, PointF p0, PointF p3) {
//时间因子t: 0~1
PointF point = new PointF();
//deCasteljau算法
point.x = deCasteljauX(i, j, t);
point.y = deCasteljauY(i, j, t);
return point;//实时返回最新计算出的点对象
}
}
/**
* deCasteljau算法
*
* @param i 阶数
* @param j 点
* @param t 时间
* @return
*/
private float deCasteljauX(int i, int j, float t) {
if (i == 1) {
return (1 - t) * mControlPoints.get(j).x + t * mControlPoints.get(j + 1).x;
}
return (1 - t) * deCasteljauX(i - 1, j, t) + t * deCasteljauX(i - 1, j + 1, t);
}
/**
* deCasteljau算法
*
* @param i 阶数
* @param j 点
* @param t 时间
* @return
*/
private float deCasteljauY(int i, int j, float t) {
if (i == 1) {
return (1 - t) * mControlPoints.get(j).y + t * mControlPoints.get(j + 1).y;
}
return (1 - t) * deCasteljauY(i - 1, j, t) + t * deCasteljauY(i - 1, j + 1, t);
}
deCasteljau算法?不懂?没关系看这里[塞尔曲线德卡斯特里奥(de Casteljau)算法及程序](http://www.programgo.com/article/54123662523/)本文采用递归方式计算多阶贝塞尔。
啊哈?这下完了吧?是嘞,至于添加到xml等等我就不说了 具体看源码有注释
仿百度生活手记自定义动态曲线时间轴 :http://download.csdn.net/detail/qq_28326953/9629305