仿直播点赞动画

前一段时间感觉直播很火,因此我就下了七八个直播软件去看了,不要问我为啥下这么多,我会告诉你我想看看哪个平台的妹子颜值高吗,好吧最终喜欢上看映客的一个妹子。妹子歌唱的很好听可惜屌丝的我涮不起礼物,只能在屏幕下方狂点赞了。好了这次当然不是讨论直播平台的妹子,而是看下直播软件点赞的效果怎样实现的。
说一下思想吧,首先利用属性动画的放大效果让生成的图片不至于太突兀的显示,接着让生成的图片沿着三阶贝塞尔曲线的轨迹去移动,在移动的过程中逐渐设置图片的透明效果至0,最后在动画结束的时候remove掉新生成的图片。

下面看下效果图吧
这里写图片描述

效果就是这么个效果,下面看具体实现吧

首先看下布局文件

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.jh.mymathsintext.MainActivity">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?actionBarSize"
        android:background="@color/colorPrimary"
        app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
        app:title="@string/app_name">

    </android.support.v7.widget.Toolbar>

    <com.jh.mymathsintext.MyRelative
        android:id="@+id/rela"
        android:layout_width="200dp"
        android:layout_height="match_parent"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="100dp"
        android:layout_below="@id/toolbar"
        android:gravity="bottom|center_horizontal">

    </com.jh.mymathsintext.MyRelative>


    <ImageView
        android:id="@+id/img"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/pl_blue"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="50dp"/>



</RelativeLayout>

布局文件没什么好讲的,接着看下具体实现,先把整体代码贴出来在分步细讲

public class MyRelative extends RelativeLayout{

    private int []drawable={R.drawable.pl_blue,R.drawable.pl_red,R.drawable.pl_yellow};

    private  LayoutParams params;

    private Random random=new Random();

    private int height,width;

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

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

    }

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

    }

    /**
     * 获取图片的大小
     */
    public void init(){
        BitmapFactory.Options options=new BitmapFactory.Options();
        options.inJustDecodeBounds=true;
        Bitmap bitmap=BitmapFactory.decodeResource(getResources(),R.drawable.pl_red,options);
        width=options.outWidth;
        height=options.outHeight;
//        width=ContextCompat.getDrawable(getContext(),R.drawable.pl_red).getIntrinsicWidth();
//        height=ContextCompat.getDrawable(getContext(),R.drawable.pl_red).getIntrinsicHeight();

        params=new LayoutParams(width, height);




    }

    /**
     * 生成图片,并设置动画
     */
    public void addView(){
        final ImageView imageView=new ImageView(getContext());
        imageView.setLayoutParams(params);
        imageView.setBackgroundResource(drawable[random.nextInt(3)]);
        addView(imageView);
        AnimatorSet set=getAnimation(imageView);//属性动画控制放大效果
        ValueAnimator valueAnimator=setPoint(imageView);//控制移动
        AnimatorSet animatorSet=new AnimatorSet();
        animatorSet.playSequentially(set,valueAnimator);//设置属性动画按顺序执行
        animatorSet.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                removeView(imageView);
            }
        });
        animatorSet.start();



    }

    /**
     * 属性动画控制放大效果
     * @param imageView
     * @return
     */
    public AnimatorSet getAnimation(ImageView imageView){
        ObjectAnimator objectAnimator1=ObjectAnimator.ofFloat(imageView,SCALE_X,0f,1f);
        ObjectAnimator objectAnimator2=ObjectAnimator.ofFloat(imageView,SCALE_Y,0f,1f);
        AnimatorSet animatorSet=new AnimatorSet();
        animatorSet.playTogether(objectAnimator1,objectAnimator2);//控制动画一起执行
        animatorSet.setDuration(500);
        return animatorSet;
    }

    /**
     * 创建贝塞尔轨迹并让图片沿着贝塞尔轨迹运行
     * @param imageView
     * @return
     */
    public ValueAnimator setPoint(final View imageView){
        MyPoint myPoint=new MyPoint(getPoint(2),getPoint(1));
        ValueAnimator valueAnimator=ValueAnimator.ofObject(myPoint,new PointF((this.getWidth()-width)/2,this.getHeight()-height),
                new PointF(random.nextInt(getWidth()),0));
        valueAnimator.setDuration(2000);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                PointF pointF= (PointF) animation.getAnimatedValue();
                Log.i("tag","dfdgdfadfsdsdd"+pointF.x);
                imageView.setX(pointF.x);
                imageView.setY(pointF.y);
                imageView.setAlpha(1-animation.getAnimatedFraction());
            }
        });

        return valueAnimator;

    }

    /**
     * 随机生成点
     * @param height
     * @return
     */
    public PointF getPoint(int height){
        PointF pointF=new PointF();
        pointF.x=random.nextInt(getWidth()-50);
        pointF.y=random.nextInt(getHeight()-50)/height;
        return pointF;
    }

}

首先需要获取一下图片的大小然后设置给新创建的imageview

 /**
     * 获取图片的大小
     */
    public void init(){
        BitmapFactory.Options options=new BitmapFactory.Options();
        options.inJustDecodeBounds=true;
        Bitmap bitmap=BitmapFactory.decodeResource(getResources(),R.drawable.pl_red,options);
        width=options.outWidth;
        height=options.outHeight;
//        width=ContextCompat.getDrawable(getContext(),R.drawable.pl_red).getIntrinsicWidth();
//        height=ContextCompat.getDrawable(getContext(),R.drawable.pl_red).getIntrinsicHeight();

        params=new LayoutParams(width, height);

    }

然后就是给新创建的imageview设置放大动画了,这里利用属性动画实现

/**
     * 属性动画控制放大效果
     * @param imageView
     * @return
     */
    public AnimatorSet getAnimation(ImageView imageView){
        ObjectAnimator objectAnimator1=ObjectAnimator.ofFloat(imageView,SCALE_X,0f,1f);
        ObjectAnimator objectAnimator2=ObjectAnimator.ofFloat(imageView,SCALE_Y,0f,1f);
        AnimatorSet animatorSet=new AnimatorSet();
        animatorSet.playTogether(objectAnimator1,objectAnimator2);//控制动画一起执行
        animatorSet.setDuration(500);
        return animatorSet;
    }

接下来就是要让新生成的imageview实现沿着三阶贝塞尔曲线轨迹去移动了,重点是获取三阶贝塞尔曲线的轨迹坐标,这个可以利用实现TypeEvaluator接口和PointF实现。这是会重写TypeEvaluator接口里的evaluate()方法,看下方法实现吧


    @Override
    public PointF evaluate(float fraction, PointF startValue, PointF endValue) {

        float timeDel=1-fraction;

        PointF pointF=new PointF();
        //三阶贝塞尔曲线公式
        pointF.x=timeDel*timeDel*timeDel*startValue.x+3*pointF1.x*timeDel*timeDel*fraction+3*pointF2.x*fraction*fraction*timeDel+
                endValue.x*fraction*fraction*fraction;
        pointF.y=timeDel*timeDel*timeDel*startValue.y+3*pointF1.y*timeDel*timeDel*fraction+3*pointF2.y*fraction*fraction*timeDel+
                endValue.y*fraction*fraction*fraction;
        return pointF;
    }

对就是在上述方法里实现获取三阶贝塞尔曲线轨迹坐标,先看下贝塞尔曲线的公式

这里写图片描述

三阶贝塞尔曲线公式如上,因为evaluate()方法里有起始点和终点,只需要在创建两个点就可以了,为了让每一个生成的imageview运行轨迹大致不相同,我们可以随机生成这两个点,代码如下所示

 /**
     * 随机生成点
     * @param height
     * @return
     */
    public PointF getPoint(int height){
        PointF pointF=new PointF();
        pointF.x=random.nextInt(getWidth()-50);
        pointF.y=random.nextInt(getHeight()-50)/height;
        return pointF;
    }

接下来需要做的事情就是将轨迹坐标赋给imageview,代码如下

 /**
     * 创建贝塞尔轨迹并让图片沿着贝塞尔轨迹运行
     * @param imageView
     * @return
     */
    public ValueAnimator setPoint(final View imageView){
        MyPoint myPoint=new MyPoint(getPoint(2),getPoint(1));
        ValueAnimator valueAnimator=ValueAnimator.ofObject(myPoint,new PointF((this.getWidth()-width)/2,this.getHeight()-height),
                new PointF(random.nextInt(getWidth()),0));
        valueAnimator.setDuration(2000);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                PointF pointF= (PointF) animation.getAnimatedValue();
                Log.i("tag","dfdgdfadfsdsdd"+pointF.x);
                imageView.setX(pointF.x);
                imageView.setY(pointF.y);
                imageView.setAlpha(1-animation.getAnimatedFraction());
            }
        });

        return valueAnimator;

    }

然后需要做的就是将放大动画和轨迹动画设置给imageview去实现即可,

 /**
     * 生成图片,并设置动画
     */
    public void addView(){
        final ImageView imageView=new ImageView(getContext());
        imageView.setLayoutParams(params);
        imageView.setBackgroundResource(drawable[random.nextInt(3)]);
        addView(imageView);
        AnimatorSet set=getAnimation(imageView);//属性动画控制放大效果
        ValueAnimator valueAnimator=setPoint(imageView);//控制移动
        AnimatorSet animatorSet=new AnimatorSet();
        animatorSet.playSequentially(set,valueAnimator);//设置属性动画按顺序执行
        animatorSet.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                removeView(imageView);
            }
        });
        animatorSet.start();



    }

注意的一点是在动画结束的时候最好将生成的imageview给移除掉,到此为止点赞效果就做出来了,别拦我,我要去跟女神表白了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值