仿映客点赞效果 点赞上升动画&&全屏点赞

仿映客点赞效果、点赞上升动画、还有全屏点赞效果、先上效果图
这里写图片描述

copy http://blog.csdn.net/qq284565035/article/details/46635697
实现分为两步
1、屏幕显示星星、动画分别是透明和缩放
2、实现贝塞尔曲线

显示星星

自定义控件、继承 RelativeLayout 并初始化

    public RisingBubbleWidget(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        // 五星气泡
        mStarDrawable = getContext().getResources().getDrawable(R.drawable.icon_five_stars);
        // 获取图片的宽高
        mStarWidth = mStarDrawable.getIntrinsicWidth();
        mStarHeight = mStarDrawable.getIntrinsicHeight();

        mParams = new LayoutParams(mStarWidth, mStarHeight);
        //设置心形的位置,这里选择屏幕下方的中间位置(基于RelativeLayout)
        mParams.addRule(ALIGN_PARENT_BOTTOM, TRUE);
        mParams.addRule(ALIGN_PARENT_RIGHT, TRUE);
        mParams.setMargins(0, 0, DensityUtility.dip2px(getContext(), STAR_RIGHT_MARGIN), 0);
        this.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                playRisingBubbleAnim();
            }
        });
    }
        @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mWidth = getMeasuredWidth();
        mHeight = getMeasuredHeight();
    }

设置动画效果

        // 放大淡入动画
        PropertyValuesHolder pScaleX = PropertyValuesHolder.ofFloat(View.SCALE_X, 0.5f, 1f);
        PropertyValuesHolder pScaleY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 0.5f, 1f);
        PropertyValuesHolder pAlpha = PropertyValuesHolder.ofFloat(View.ALPHA, 0.5f, 1f);
        PropertyValuesHolder pRotation = PropertyValuesHolder.ofFloat(View.ROTATION, 0, getRandomDegree());
        mEnterAnim = ObjectAnimator.ofPropertyValuesHolder(starImageView, pScaleX, pScaleY, pAlpha, pRotation);
        mEnterAnim.setDuration(100);
        mEnterAnim.setInterpolator(new AccelerateInterpolator());

实现贝塞尔曲线动画

首先简单介绍一下贝塞尔曲线
P代表一个二维坐标点,很容易可以对应到PointF,而t代表是目标运行的时间,取值[0,1]。
P0是起始点,P3是终点,而P1和P2是趋向点。大概可以理解为一个正弦曲线的最高点和最低点。

1.使用插值器定义每一秒的目标的位置

初始化BezierEvaluator时将两个中间点传入

public class BezierEvaluator implements TypeEvaluator<PointF> {

    @Override
    public PointF evaluate(float time, PointF startValue, PointF endValue) {
        PointF point1 = new PointF((startValue.x + endValue.x) / 2, (startValue.y + endValue.y) / 2);
        if (time < 0 || time > 1) {
            throw new IllegalArgumentException("time must between 0 and 1");
        }
        float timeLeft = 1.0f - time;
        PointF pointF = new PointF();
        pointF.x = timeLeft * timeLeft * startValue.x
                + 2 * time * timeLeft * point1.x
                + time * time * endValue.x;
        pointF.y = timeLeft * timeLeft * startValue.y
                + 2 * time * timeLeft * point1.y
                + time * time * endValue.y;
        return pointF;
    }
}

2.将插值器插入到动画中

初始化ValueAnimator时将起点和终点的值传入

        //贝塞尔曲线动画
        BezierEvaluator bezierEvaluator = new BezierEvaluator();
        mBezierAnim = ValueAnimator.ofObject(bezierEvaluator,
                new PointF(mWidth - mStarWidth - DensityUtility.dip2px(getContext(), STAR_RIGHT_MARGIN), mHeight - mStarHeight),
                new PointF(2 * mWidth / 3 + mRandom.nextInt(mWidth / 3), (mHeight - mStarHeight) / 2));
        mBezierAnim.setDuration(2500);
        mBezierAnim.setInterpolator(new AccelerateDecelerateInterpolator());

3.增加动画更新监听器,否则并无卵用

 mBezierAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                //这里获取到贝塞尔曲线计算出来的x,y赋值给view,这样就能让五星随着曲线走
                PointF pointF = (PointF) valueAnimator.getAnimatedValue();
                starImageView.setX(pointF.x);
                starImageView.setY(pointF.y);
                //加上 alpha 动画
                starImageView.setAlpha(1 - valueAnimator.getAnimatedFraction());
            }
        });
        mBezierAnim.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {

            }

            @Override
            public void onAnimationEnd(Animator animator) {
                //因为不停的add,导致子view只增不减,所以在view动画结束后remove
                removeView(starImageView);
            }

            @Override
            public void onAnimationCancel(Animator animator) {

            }

            @Override
            public void onAnimationRepeat(Animator animator) {

            }
        });

4.将两个动画合并在一起、

        mStarAnimSet = new AnimatorSet();
        mStarAnimSet.playSequentially(mEnterAnim, mBezierAnim);
        mStarAnimSet.start();

下面是完整代码

package com.rvitemtouch.sun.risingapplication.widget;

import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.PointF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AccelerateInterpolator;
import android.widget.ImageView;
import android.widget.RelativeLayout;


import com.rvitemtouch.sun.risingapplication.R;

import java.util.Random;


/**
 * Created by sun on 2016/6/16.
 * 上升气泡动画效果
 */
public class RisingBubbleWidget extends RelativeLayout implements BaseLayoutInterface {
    private static final String TAG = "RisingBubbleWidget";
    private int mStarWidth;
    private int mStarHeight;
    // widget 的width
    private int mWidth;
    // widget 的height
    private int mHeight;
    private Drawable mStarDrawable;
    private Random mRandom = new Random();
    private static final int STAR_RIGHT_MARGIN = 57;
    private ObjectAnimator mEnterAnim;
    private ValueAnimator mBezierAnim;
    private AnimatorSet mStarAnimSet;
    private LayoutParams mParams;

    public RisingBubbleWidget(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public RisingBubbleWidget(Context context) {
        super(context);
        init();
    }

    public RisingBubbleWidget(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        // 五星气泡
        mStarDrawable = getContext().getResources().getDrawable(R.drawable.icon_five_stars);
        // 获取图片的宽高
        mStarWidth = mStarDrawable.getIntrinsicWidth();
        mStarHeight = mStarDrawable.getIntrinsicHeight();

        mParams = new LayoutParams(mStarWidth, mStarHeight);
        mParams.addRule(ALIGN_PARENT_BOTTOM, TRUE);
        mParams.addRule(ALIGN_PARENT_RIGHT, TRUE);
        mParams.setMargins(0, 0, DensityUtility.dip2px(getContext(), STAR_RIGHT_MARGIN), 0);
        this.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                playRisingBubbleAnim();
            }
        });
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mWidth = getMeasuredWidth();
        mHeight = getMeasuredHeight();
    }

    /**
     * 开始上升五星气泡动画
     */
    public void playRisingBubbleAnim() {
        ImageView starImageView = new ImageView(getContext());
        starImageView.setImageDrawable(mStarDrawable);
        starImageView.setLayoutParams(mParams);

        // 添加五星
        addView(starImageView);
        startRisingAnim(starImageView);
    }

    /**
     * 播放上升动画
     */
    private void startRisingAnim(final ImageView starImageView) {
        // 放大淡入动画
        PropertyValuesHolder pScaleX = PropertyValuesHolder.ofFloat(View.SCALE_X, 0.5f, 1f);
        PropertyValuesHolder pScaleY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 0.5f, 1f);
        PropertyValuesHolder pAlpha = PropertyValuesHolder.ofFloat(View.ALPHA, 0.5f, 1f);
        PropertyValuesHolder pRotation = PropertyValuesHolder.ofFloat(View.ROTATION, 0, getRandomDegree());
        mEnterAnim = ObjectAnimator.ofPropertyValuesHolder(starImageView, pScaleX, pScaleY, pAlpha, pRotation);
        mEnterAnim.setDuration(100);
        mEnterAnim.setInterpolator(new AccelerateInterpolator());

        //贝塞尔曲线动画
        BezierEvaluator bezierEvaluator = new BezierEvaluator();
        mBezierAnim = ValueAnimator.ofObject(bezierEvaluator,
                new PointF(mWidth - mStarWidth - DensityUtility.dip2px(getContext(), STAR_RIGHT_MARGIN), mHeight - mStarHeight),
                new PointF(2 * mWidth / 3 + mRandom.nextInt(mWidth / 3), (mHeight - mStarHeight) / 2));
        mBezierAnim.setDuration(2500);
        mBezierAnim.setInterpolator(new AccelerateDecelerateInterpolator());
        mBezierAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                //这里获取到贝塞尔曲线计算出来的x,y赋值给view,这样就能让五星随着曲线走
                PointF pointF = (PointF) valueAnimator.getAnimatedValue();
                starImageView.setX(pointF.x);
                starImageView.setY(pointF.y);
                //加上 alpha 动画
                starImageView.setAlpha(1 - valueAnimator.getAnimatedFraction());
            }
        });
        mBezierAnim.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {

            }

            @Override
            public void onAnimationEnd(Animator animator) {
                //因为不停的add,导致子view只增不减,所以在view动画结束后remove
                removeView(starImageView);
            }

            @Override
            public void onAnimationCancel(Animator animator) {

            }

            @Override
            public void onAnimationRepeat(Animator animator) {

            }
        });

        mStarAnimSet = new AnimatorSet();
        mStarAnimSet.playSequentially(mEnterAnim, mBezierAnim);
        mStarAnimSet.start();
    }

    /**
     * 获取随机角度
     */
    private float getRandomDegree() {
        float degree;
        int randomInt = mRandom.nextInt(5);
        switch (randomInt) {
            case 0:
                degree = -15f;
                break;
            case 1:
                degree = -30f;
                break;
            case 2:
                degree = 0f;
                break;
            case 3:
                degree = 15f;
                break;
            case 4:
                degree = 30f;
                break;
            default:
                degree = 30f;
                break;
        }
        return degree;
    }

    @Override
    public void onAdded() {

    }

    @Override
    public void onResume() {

    }

    @Override
    public void onPause() {

    }

    /**
     * 防止内存溢出、
     */
    @Override
    public void onDestroy() {
        if (mEnterAnim != null) {
            mEnterAnim.removeAllListeners();
            mEnterAnim.cancel();
        }
        if (mBezierAnim != null) {
            mBezierAnim.removeAllListeners();
            mBezierAnim.cancel();
        }
        if (mStarAnimSet != null) {
            mStarAnimSet.removeAllListeners();
            mStarAnimSet.cancel();
        }
    }

    @Override
    public void onStop() {

    }

    @Override
    public void onStart() {

    }
}

全屏点赞

原理很简单、找出点击的位置、然后将view add进去、等动画执行完后再removeView
下面是完整代码

package com.rvitemtouch.sun.risingapplication;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.view.MotionEventCompat;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.RelativeLayout;

import java.util.Random;

public class ZanActivity extends Activity {
    private RelativeLayout zan_container;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_zan);
        zan_container = (RelativeLayout) findViewById(R.id.zan_container);
        zan_container.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                float x = event.getX();
                float y = event.getY();

                final int action = MotionEventCompat.getActionMasked(event);
                switch (action) {
                    case MotionEvent.ACTION_DOWN://单点触摸动作
                        break;
                    case MotionEvent.ACTION_UP://单点触摸离开动作
                        ImageView imageView = new ImageView(ZanActivity.this);
                        RelativeLayout.LayoutParams param = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
                        final int width = imageView.getWidth();
                        final int height = imageView.getHeight();
                        param.setMargins((int) x - width / 2, (int) y - height / 2, 0, 0);
                        imageView.setLayoutParams(param);
                        imageView.setImageResource(R.drawable.zan_light_done);
                        zan_container.addView(imageView);
                        startAnim(x, y, imageView);
                        break;
                    case MotionEvent.ACTION_MOVE://触摸点移动动作
                        break;
                    case MotionEvent.ACTION_CANCEL://触摸动作取消
                        break;
                    case MotionEvent.ACTION_POINTER_DOWN://多点触摸动作
                        break;
                    case MotionEvent.ACTION_POINTER_UP://多点离开动作
                        break;
                }
                return true;
            }
        });
    }

    private void startAnim(final float x, final float y, final ImageView imageView) {

        RotateAnimation rotateAnimation = createRandom();
        AnimationSet animSet = new AnimationSet(true);
        AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0);
        rotateAnimation.setDuration(600);//设置动画持续时间
        alphaAnimation.setDuration(1000);//设置动画持续时间
        alphaAnimation.setFillAfter(true);//动画执行完后是否停留在执行完的状态
        /** 常用方法 */
//        animation.setRepeatCount(int repeatCount);//设置重复次数
        //animation.setStartOffset(long startOffset);//执行前的等待时间
        animSet.addAnimation(rotateAnimation);
        animSet.addAnimation(alphaAnimation);
        rotateAnimation.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                Log.i("SHF", "x-->" + x + "y--->" + y);

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                if (zan_container.getChildCount() > 0) {
                    //Attempt to read from field 'int android.view.View.mViewFlags' on a null
                    //加动画图片这边也在移除动画解决办法
                    new Handler().post(new Runnable() {
                        public void run() {
                            imageView.clearAnimation();
                            zan_container.removeView(imageView);
                        }
                    });
                }
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
            }
        });
        imageView.startAnimation(animSet);
    }

    /**
     * 随机角度
     *
     * @return
     */
    private RotateAnimation createRandom() {
        int i = new Random().nextInt(5);
        switch (i) {
            case 0:
                return new RotateAnimation(0f, 15f, Animation.RELATIVE_TO_SELF,
                        0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
            case 1:
                return new RotateAnimation(0f, 30f, Animation.RELATIVE_TO_SELF,
                        0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
            case 2:
                return new RotateAnimation(0f, 0f, Animation.RELATIVE_TO_SELF,
                        0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
            case 3:
                return new RotateAnimation(0f, -15f, Animation.RELATIVE_TO_SELF,
                        0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
            case 4:
                return new RotateAnimation(0f, -30f, Animation.RELATIVE_TO_SELF,
                        0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        }
        return new RotateAnimation(0f, 30f, Animation.RELATIVE_TO_SELF,
                0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
    }
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值