因为新的项目中要实现海底上升气泡的效果当做手机下半面的背景,需要气泡随机大小随机位置移动。说是随机移动,但是终点要控制所有的气泡都要回归到终点位置X轴的中点。所以我选择了用二阶的贝塞尔曲线和属性动画来实现。先看下效果。
因为背景图选择的是深色图,所以效果有些不明显。大家将就着看。
在实现这个效果之前,公司的动效设计师说气泡是三种气泡,分别有不同的颜色以及阴影边缘,所以他给我们提供气泡的素材。这也就省去了画气泡的时间。
首先我们在自定义view中添加了十一个不同的气泡图片,并且我又实例了一个集合用来存放LayoutParams,用来实现气泡的不同大小。
private ValueAnimator getBezierValueAnimator(final View target) {
// 初始化贝塞尔估值器 //随机产生两个点,以确定一条3阶贝塞尔
曲线 BezierEvaluator evaluator = new BezierEvaluator(getPointF(), getPointF());
ValueAnimator animator= ValueAnimator.ofObject(evaluator, new PointF(random.nextInt(1000), 1000), new PointF(random.nextInt(500)+300, 0)); animator.setTarget(target); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override public void onAnimationUpdate(ValueAnimator valueAnimator) {
// 这里获取到贝塞尔曲线计算出来的的x y值 赋值给view 这样就能让气泡随着曲线走啦
PointF pointF = (PointF) valueAnimator.getAnimatedValue(); target.setX(pointF.x); target.setY(pointF.y); }
});
animator.setDuration(6000); return animator;}
上面的方法是贝塞尔曲线的灵魂,我们向这个方法中添加view,然后确定控制点的位置。
二阶贝塞尔曲线还是很简单的,只需要确定三个点的位置。也就是起点,终点和两个点中间的控制点,然后根据贝塞尔估值器转化为贝塞尔的路径。那么就可以了。
从上面的方法,可以看到我们用到了属性动画,我们监听了动画的变化,然后根据每次变化将贝塞尔曲线得到的点的位置赋值给view,那么就能够让view按照贝塞尔曲线移动了。具体的移动时间可以自己控制。
private PointF getPointF() { PointF pointF = new PointF();
pointF.x = random.nextInt(ScreenUtils.getScreenWidth(mContext));
pointF.y = random.nextInt(300)+100; return pointF;}
这个方法是我们用来控制中间的控制点的。X轴上的点是在屏幕的宽度之间随机选取的。这样会实现曲线分布的很均匀。然后Y轴上的坐标,为了能够让曲线在中间位置让用户看的很随机。我特别选取了Y轴在自定义view的中间位置。这样曲线在用户的视线内会有很均匀的变化。这个点也就是二阶贝塞尔曲线的中间点位置。
public void startBallAnim() {
final ImageView imageView = new ImageView(mContext);
imageView.setBackgroundResource(mList.get(random.nextInt(mList.size())));
imageView.setLayoutParams(lp.get(random.nextInt(lp.size())));
addView(imageView);
AnimatorSet finalSet = new AnimatorSet();
ValueAnimator bezierValueAnimator = getBezierValueAnimator(imageView);
//贝塞尔曲线路径动画
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView,"alpha",random.nextFloat(),0f);
objectAnimator.setDuration(6000);
finalSet.playSequentially(bezierValueAnimator);
finalSet.setInterpolator(new LinearInterpolator());
finalSet.setTarget(imageView);
finalSet.addListener(new AnimatorListenerAdapter() {
@Override public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation); removeView((imageView));//删除气泡 }
});
finalSet.start();
objectAnimator.start();}
这个方法是在自定义view刚开始实例化就开始调用的。这样在用户进入界面的时候,就会触发气泡开始向上升起。这里还是用到了属性动画,渐变的属性动画。初衷是让气泡越往上面移动越透明,最后淡出。然后在动画结束的时候,将这个view remove掉,不然这个动画会让气泡一直一直的出来,会对内存有很大的损耗。
然后在自定义view实例化的时候调用这个开始方法。就会有源源不断的气泡从底部升上来。
有什么问题可以私聊我或者公聊 哈哈哈哈