之前写过一个 基本属性动画 的简单介绍,这里再简单试用一下。属性动画的案例有很多很多都是特别炫的,其实重点还是思路,这里就提供一些属性动画的思路,思路可能很粗糙,但是效果实现了~
先看一下今天实现的第一种效果。
这里是两张图片,用动画集合简单的实现了一个动画效果。分析一下需要用到的动画,商品页面有:透明动画,旋转动画,还有一个缩放动画,暂时就能看出这么多,看一下代码实现。
//透明度动画
ObjectAnimator firstAlphaAnim = ObjectAnimator.ofFloat(first_view, "alpha", 1.0f, 0.7f);
firstAlphaAnim.setDuration(300);
//旋转动画1
ObjectAnimator firstRotationXanim = ObjectAnimator.ofFloat(first_view, "rotationX", 0f,20f,0f);
firstRotationXanim.setDuration(600);
//缩放动画
ObjectAnimator firstScaleXAnim = ObjectAnimator.ofFloat(first_view, "ScaleX", 1.0f, 0.8f);
firstScaleXAnim.setDuration(300);
ObjectAnimator firstScaleYAnim = ObjectAnimator.ofFloat(first_view, "ScaleY", 1.0f, 0.8f);
firstScaleYAnim.setDuration(300);
AnimatorSet set = new AnimatorSet();
//一起执行
set.playTogether(
firstScaleXAnim,
firstScaleYAnim,
firstAlphaAnim,
firstRotationXanim
);
set.start();
这里发现,应该是还少一个平移动画,才能让view贴到屏幕上边。由于刚才缩放高度减少了0.2*view的高度,上下各0.1,所以我们需要向上平移0.1个控件的高度。
//由于缩放造成离顶部有一个距离,需要平移
ObjectAnimator firstTranslationYAnim = ObjectAnimator.ofFloat(first_view, "translationY", 0f, -0.1f*first_view.getHeight());
firstTranslationYAnim.setDuration(300);
好了,一个view解决了,剩下就是规格页面的一个显示并平移,规格页面初始是不显示的,在商品页面动画开始的时候,显示规格页面,并从自己的底部移动到自己原来的位置。
//第二个view和第一个view动画同时开始执行
ObjectAnimator secondTranslationYAnim = ObjectAnimator.ofFloat(second_view, "translationY", second_view.getHeight(), 0f);
secondTranslationYAnim.setDuration(300);
secondTranslationYAnim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
second_view.setVisibility(View.VISIBLE);
bt.setClickable(false);
bt1.setClickable(false);
}
});
最后大功告成。基本的属性动画又使用了一次,是不是不过瘾,发现这个Demo 有两个按钮,之前一直都是点的 显示 按钮会出现基础动画的使用,那个赞一个是什么鬼。
这种常见的刷鲜花效果,这里依旧是属性动画实现的,还记得在 基本属性动画中说过的一个估值器,可以让View以抛物线的轨迹移动,这里也是用到了估值器,一起来看一下怎么实现的把~
首先我们在点击按钮是需要添加心图片,并简单的做了内存优化。一些值的初始化就在 源码 中看吧
//点击按钮时调用
public void addLoveIcon(){
final ImageView iv ;
//添加心形,并开始执行动画
iv= (ImageView) Recycle();
iv.setImageDrawable(drawables[random.nextInt(3)]);
//将iv添加到父容器底部、水平居中位置
iv.setLayoutParams(params);
addView(iv);
//开始属性动画:平移、透明度渐变、缩放动画
AnimatorSet set = getAnimator(iv);
//监听动画执行完毕,将iv移除或者复用
set.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
removeView(iv);
}
});
set.start();
}
List<View> list=new ArrayList<>();
//重新removeView将要删除的View保存起来
@Override
public void removeView(View view) {
list.add(view);
super.removeView(view);
}
//添加view的时候先看有没有之前保存的imageView
private View Recycle() {
if (list.isEmpty()) {
ImageView iv = new ImageView(getContext());
// {//固定位置
// startX=(mWidth - dWidth) / 2;
//
// }
{//随机位置
startX = random.nextInt(mWidth);
iv.setX(startX);
iv.setY(mHeight - dHeight);
}
return iv;
} else {
View v = list.get(0);
//这里是在复用的时候如果执行第一个缩放动画,位置会有问题,所以这里设置一下初始位置
// {//固定位置
// startX=(mWidth - dWidth) / 2;
// v.setX(startX);
// v.setY(mHeight - dHeight);
// }
{//随机位置
startX = random.nextInt(mWidth);
v.setX(startX);
v.setY(mHeight - dHeight);
}
list.remove(v);
return v;
}
}
这里的固定位置和随机位置是图片初始的位置,现在是随机位置,如果要使用固定为在需要将这里面代码重新注释,把随机位置的代码块注释掉,然后把源码 81行 82 行 params的设置解开。在添加的时候调用getAnimator()来设置imageView动画。
// 得到一个iv的动画集合
private AnimatorSet getAnimator(ImageView iv) {
//平移、透明度渐变、缩放动画
//1.alpha动画
ObjectAnimator alpha = ObjectAnimator.ofFloat(iv, "alpha", 0.3f,1f);
//2.缩放动画
ObjectAnimator scaleX = ObjectAnimator.ofFloat(iv, "scaleX", 0.5f,1f);
ObjectAnimator scaleY = ObjectAnimator.ofFloat(iv, "scaleY", 0.5f,1f);
//三个动画同时执行
AnimatorSet enter = new AnimatorSet();
enter.setDuration(200);
enter.playTogether(alpha,scaleX,scaleY);
//设置平移的曲线动画---贝塞尔曲线
ValueAnimator bezierAnimator = getBezierValueAnimator(iv);
AnimatorSet set = new AnimatorSet();
//按序列执行
set.playSequentially(enter, bezierAnimator);
//加速因子,使用插值器
set.setInterpolator(interpolators[random.nextInt(4)]);
set.setTarget(iv);
return set;
}
先执行原地的缩放,透明度变化的动画,再执行估值器的动画。
//得到一个贝塞尔曲线动画
private ValueAnimator getBezierValueAnimator(final ImageView iv) {
//根据贝塞尔公式确定四个点(起始点p0,拐点1p1,拐点2p2,终点p3)
PointF pointF0 = new PointF(startX, mHeight - dHeight);//屏幕宽度随机的为起点
PointF pointF3 = new PointF(random.nextInt(mWidth), 0);
PointF pointF1 = getPointF(1);
PointF pointF2 = getPointF(2);
//估值器Evaluator,来控制view的行驶路径(不断地修改point.x,point.y)
BezierEvaluator evaluator = new BezierEvaluator(pointF1, pointF2);
//属性动画不仅仅可以改变view的属性,还可以改变自定义的属性(比如Point)
ValueAnimator animator = ValueAnimator.ofObject(evaluator, pointF0, pointF3);
animator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
PointF pointF = (PointF) animation.getAnimatedValue();
iv.setX(pointF.x);
iv.setY(pointF.y);
iv.setAlpha(1 - animation.getAnimatedFraction());//1~0 百分比
}
});
animator.setDuration(4000);
return animator;
}
这里是对 起点,终点,和两个控制点的初始化,这样就可以形成一个三阶贝塞尔曲线,这里会间接的把四个点传过去,在BezierEvaluator计算X,Y的值,直接套公式,通过监听获取返回的坐标值。
最后附上 源码
这里只是属性动画基本的一个使用,如果其中有错误还请指出,我会尽快修改文章,并改正自己的理解,谢谢。