Android实现简单点赞动画

作者:碧云天丶 时间:2021-05-25 11:12:20 

本文实例为大家分享了Android实现简单点赞动画的具体代码,供大家参考,具体内容如下

思路

1、找到ActivityDecorViewRootView
2、确定点赞控件位于屏幕中的坐标值
3、将点赞效果View加入到RootView中, 给效果View添加自己想要的动画效果.
4、重复点击时候, 需要将效果View先移除掉再重新加入到RootView中.

代码


/**
* 普通点赞效果, 点击控件后出现一个View上浮
*/
public class ViewLikeUtils {
   public interface ViewLikeClickListener {
       /**
        * @param view          被点赞的按钮
        * @param toggle        开关
        * @param viewLikeUtils 工具类本身
        */
       void onClick(View view, boolean toggle, ViewLikeUtils viewLikeUtils);
   }

// 被点击的按钮
   private View mClickView;
   private View mAnimView;
   private ViewLikeClickListener mListener;
   private boolean toggle = false; // 点击开关标识
   private int mX; // 距离屏幕左侧距离
   private int mY; // 距离屏幕顶端距离, 越往下数值越大

/**
    * @param mClickView 被点击的View
    * @param mAnimView  点赞后, 向上浮动的View
    * @param mListener  被点击的View,点击后的回调事件.
    */
   public ViewLikeUtils(View mClickView, View mAnimView, @NonNull ViewLikeClickListener mListener) {
       this.mClickView = mClickView;
       this.mAnimView = mAnimView;
       this.mListener = mListener;
       initListener();
   }

/**
    * 设置View的监听
    */
   private void initListener() {
       mClickView.setOnTouchListener(new View.OnTouchListener() {
           @Override
           public boolean onTouch(View view, MotionEvent motionEvent) {
               if (motionEvent.getAction() == MotionEvent.ACTION_UP || motionEvent.getAction() == MotionEvent.ACTION_CANCEL) {
                   getLocation(); // 获取被点击View的坐标
                   toggle = !toggle;
                   if (mListener != null) {
                       mListener.onClick(mClickView, toggle, ViewLikeUtils.this);
                   }
                   // mView.performClick();
               }
               // 正常的OnClickListener将无法调用
               return true;
           }
       });
   }

/**
    * 获取View在屏幕中的坐标
    */
   private void getLocation() {
       int[] mLocation = new int[2];
       mClickView.getLocationOnScreen(mLocation);
       mX = mLocation[0];
       mY = mLocation[1];
   }

/**
    * 开始动画
    */
   private void startAnim(ValueAnimator valueAnimator) {
       valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
           @Override
           public void onAnimationUpdate(ValueAnimator valueAnimator) {
               mAnimView.setAlpha(1 - (Float) valueAnimator.getAnimatedFraction());
               FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) mAnimView.getLayoutParams();
               params.topMargin = (int) (mY - mAnimView.getMeasuredHeight() - 100 * valueAnimator.getAnimatedFraction());
               mAnimView.setLayoutParams(params);
           }
       });
       valueAnimator.addListener(new Animator.AnimatorListener() {
           @Override
           public void onAnimationStart(Animator animator) {

}

@Override
           public void onAnimationEnd(Animator animator) {
               removeChildView(mAnimView);
           }

@Override
           public void onAnimationCancel(Animator animator) {

}

@Override
           public void onAnimationRepeat(Animator animator) {

}
       });
       valueAnimator.start();
   }

/**
    * 将上浮控件添加到屏幕中
    *
    * @param animview
    */
   private void addAnimView(View animview) {
       Activity activityFromView = getActivityFromView(mClickView);
       if (activityFromView != null) {
           FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
           FrameLayout mRootView = (FrameLayout) activityFromView.getWindow().getDecorView().getRootView();
           mRootView.addView(animview, params);
           // 测量浮动View的大小
           animview.measure(0, 0);
           params.topMargin = (int) (mY - animview.getMeasuredHeight());
           params.leftMargin = mX + mClickView.getMeasuredWidth() / 2 - animview.getMeasuredHeight() / 2;
           animview.setLayoutParams(params);
       }
   }

/**
    * 开始动画
    */
   public void startLikeAnim(ValueAnimator valueAnimator) {
       removeChildView(mAnimView);
       addAnimView(mAnimView);
       startAnim(valueAnimator);
   }

/**
    * 获取Activity
    *
    * @param view
    * @return
    */
   public Activity getActivityFromView(View view) {
       if (null != view) {
           Context context = view.getContext();
           while (context instanceof ContextWrapper) {
               if (context instanceof Activity) {
                   return (Activity) context;
               }
               context = ((ContextWrapper) context).getBaseContext();
           }
       }
       return null;
   }

/**
    * 将子View从父容器中去除
    */
   private void removeChildView(View mChildView) {
       ViewGroup parentViewGroup = (ViewGroup) mChildView.getParent();
       if (parentViewGroup != null) {
           parentViewGroup.removeView(mChildView);
       }
   }
}

使用


// 效果View
val textView = TextView(this@MainActivity2)
textView.text = "+1"
textView.setTextColor(Color.RED)
textView.textSize = mBtn.textSize
// 效果View动画
val animator = ValueAnimator.ofInt(10, 200)
animator.duration = 800
ViewLikeUtils(findViewById<Button>(R.id.btn_anim), textView) { clickView, toggle, mUtils ->
   // 开始动画
   mUtils.startLikeAnim(animator)
}

效果

Android实现简单点赞动画

贝塞尔动画点赞效果

思路其实差不多, 具体看代码


public class ViewLikeBesselUtils {
   public interface ViewLikeClickListener {
       /**
        * @param view                被点赞的按钮
        * @param toggle              开关
        * @param viewLikeBesselUtils 工具类本身
        */
       void onClick(View view, boolean toggle, ViewLikeBesselUtils viewLikeBesselUtils);
   }
   // 被点击的按钮
   private View mClickView;
   private View[] mAnimViews;
   private ViewLikeClickListener mListener;
   private boolean toggle = false; // 点击开关标识
   private int mX; // 距离屏幕左侧距离
   private int mY; // 距离屏幕顶端距离, 越往下数值越大
   private Random mRandom = new Random(); // 随机数
   /**
    * @param mClickView 被点击的View
    * @param mAnimViews 点赞后, 向上浮动的View数组
    * @param mListener  被点击的View,点击后的回调事件.
    */
   public ViewLikeBesselUtils(View mClickView, View[] mAnimViews, @NonNull ViewLikeClickListener mListener) {
       this.mClickView = mClickView;
       this.mAnimViews = mAnimViews;
       this.mListener = mListener;
       initListener();
   }
   /**
    * 设置View的监听
    */
   private void initListener() {
       mClickView.setOnTouchListener(new View.OnTouchListener() {
           @Override
           public boolean onTouch(View view, MotionEvent motionEvent) {
               if (motionEvent.getAction() == MotionEvent.ACTION_UP || motionEvent.getAction() == MotionEvent.ACTION_CANCEL) {
                   getLocation(); // 获取被点击View的坐标
                   toggle = !toggle;
                   if (mListener != null) {
                       mListener.onClick(mClickView, toggle, ViewLikeBesselUtils.this);
                   }
                   // mView.performClick();
               }
               // 正常的OnClickListener将无法调用
               return true;
           }
       });
   }
   /**
    * 获取View在屏幕中的坐标
    */
   private void getLocation() {
       int[] mLocation = new int[2];
       mClickView.getLocationInWindow(mLocation);
       mX = mLocation[0];
       mY = mLocation[1];
   }
   /**
    * 开始动画
    *
    * @param mAnimView
    */
   private void startAnim(View mAnimView, int mTime) {
       AnimatorSet animatorSet = new AnimatorSet();
       ArrayList<BaseInterpolator> interpolators = new ArrayList<>();
       interpolators.add(new AccelerateInterpolator());
       interpolators.add(new DecelerateInterpolator());
       interpolators.add(new AccelerateDecelerateInterpolator());
       interpolators.add(new LinearInterpolator());
       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
           animatorSet.setInterpolator(interpolators.get(mRandom.nextInt(4)));
       }
       // 合并动画
       animatorSet.playTogether(getAnimationSet(mAnimView), getBezierAnimatorSet(mAnimView));
       animatorSet.setTarget(mAnimView);
       animatorSet.setDuration(mTime);
       animatorSet.addListener(new Animator.AnimatorListener() {
           @Override
           public void onAnimationStart(Animator animator) {
           }
           @Override
           public void onAnimationEnd(Animator animator) {
               removeChildView(mAnimView);
           }
           @Override
           public void onAnimationCancel(Animator animator) {
           }
           @Override
           public void onAnimationRepeat(Animator animator) {
           }
       });
       animatorSet.start();
   }
   /**
    * 将上浮控件添加到屏幕中
    *
    * @param animview
    */
   private void addAnimView(View animview) {
       Activity activityFromView = getActivityFromView(mClickView);
       if (activityFromView != null) {
           FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
           FrameLayout mRootView = (FrameLayout) activityFromView.getWindow().getDecorView().getRootView();
           mRootView.addView(animview, params);
       }
   }
   /**
    * 开始动画
    */
   public void startLikeAnim() {
       for (View mAnimView : mAnimViews) {
           removeChildView(mAnimView);
           addAnimView(mAnimView);
           startAnim(mAnimView, mRandom.nextInt(1500));
       }
   }
   /**
    * 获取属性动画
    */
   private AnimatorSet getAnimationSet(View mView) {
       ObjectAnimator scaleX = ObjectAnimator.ofFloat(mView, "scaleX", 0.4f, 1f);
       ObjectAnimator scaleY = ObjectAnimator.ofFloat(mView, "scaleY", 0.4f, 1f);
       ObjectAnimator alpha = ObjectAnimator.ofFloat(mView, "alpha", 1f, 0.2f);
       AnimatorSet animatorSet = new AnimatorSet();
       animatorSet.playTogether(scaleX, scaleY, alpha);
       return animatorSet;
   }
   /**
    * 获取贝塞尔动画
    */
   private ValueAnimator getBezierAnimatorSet(View mView) {
       // 测量view
        mView.measure(0, 0);
       // 屏幕宽
       int width = getActivityFromView(mClickView).getWindowManager().getDefaultDisplay().getWidth();
       int mPointF0X = mX + mRandom.nextInt(mView.getMeasuredWidth());
        int mPointF0Y = mY - mView.getMeasuredHeight()/2;
       // 起点
       PointF pointF0 = new PointF(mPointF0X, mPointF0Y);
       // 终点
       PointF pointF3 = new PointF(mRandom.nextInt(width - 100), 0f);
       // 第二点
       PointF pointF1 = new PointF(mRandom.nextInt(width - 100), (float) (mY * 0.7));
       // 第三点
       PointF pointF2 = new PointF(mRandom.nextInt(width - 100), (float) (mY * 0.3));
       BezierEvaluator be = new BezierEvaluator(pointF1, pointF2);
       ValueAnimator bezierAnimator = ValueAnimator.ofObject(be, pointF0, pointF3);
       bezierAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
           @Override
           public void onAnimationUpdate(ValueAnimator valueAnimator) {
               PointF pointF = (PointF) valueAnimator.getAnimatedValue();
               mView.setX(pointF.x);
               mView.setY(pointF.y);
           }
       });
       return bezierAnimator;
   }
   /**
    * 获取Activity
    *
    * @param view
    * @return
    */
   public Activity getActivityFromView(View view) {
       if (null != view) {
           Context context = view.getContext();
           while (context instanceof ContextWrapper) {
               if (context instanceof Activity) {
                   return (Activity) context;
               }
               context = ((ContextWrapper) context).getBaseContext();
           }
       }
       return null;
   }
   /**
    * 将子View从父容器中去除
    */
   private void removeChildView(View mChildView) {
       ViewGroup parentViewGroup = (ViewGroup) mChildView.getParent();
       if (parentViewGroup != null) {
           parentViewGroup.removeView(mChildView);
       }
   }
}
public class BezierEvaluator implements TypeEvaluator<PointF> {
   /**
    * 这2个点是控制点
    */
   private PointF point1;
   private PointF point2;

public BezierEvaluator(PointF point1, PointF point2) {
       this.point1 = point1;
       this.point2 = point2;
   }

/**
    * @param t
    * @param point0 初始点
    * @param point3 终点
    * @return
    */
   @Override
   public PointF evaluate(float t, PointF point0, PointF point3) {
       PointF point = new PointF();
       point.x = point0.x * (1 - t) * (1 - t) * (1 - t)
               + 3 * point1.x * t * (1 - t) * (1 - t)
               + 3 * point2.x * t * t * (1 - t) * (1 - t)
               + point3.x * t * t * t;
       point.y = point0.y * (1 - t) * (1 - t) * (1 - t)
               + 3 * point1.y * t * (1 - t) * (1 - t)
               + 3 * point2.y * t * t * (1 - t) * (1 - t)
               + point3.y * t * t * t;
       return point;
   }
}

使用


mBtn = findViewById(R.id.btn_anim)
val mTVS = arrayOfNulls<TextView>(200)
for (i in 0..199) {
   val mTV = TextView(this@MainActivity2)
   mTV.text = "赞"
   mTV.setTextColor(Color.RED)
   mTV.textSize = mBtn.textSize
   mTVS[i] = mTV
}
ViewLikeBesselUtils(mBtn, mTVS) { view, toggle, viewLikeBesselUtils ->
   viewLikeBesselUtils.startLikeAnim()
}

效果

Android实现简单点赞动画

来源:https://blog.csdn.net/MoLiao2046/article/details/119784407

标签:Android,点赞
0
投稿

猜你喜欢

  • SpringBoot详细讲解yaml配置文件的用法

    2022-04-21 16:29:33
  • 一文搞懂Java中的序列化与反序列化

    2021-11-22 00:26:45
  • Intent传递对象之Serializable和Parcelable的区别

    2022-05-27 04:02:42
  • springcloud整合openfeign使用实例详解

    2022-10-05 08:51:52
  • 利用adt-bundle轻松搭建Android开发环境与Hello world(Windows)

    2022-09-05 14:35:18
  • c# 重载WndProc,实现重写“最小化”的实现方法

    2022-10-22 10:16:13
  • Android自定义顶部导航栏控件实例代码

    2022-02-11 13:43:16
  • 详解android 人脸检测你一定会遇到的坑

    2023-03-10 15:24:34
  • 轻松学习C#的String类

    2021-06-21 02:03:06
  • SpringFramework应用接入Apollo配置中心过程解析

    2021-08-30 09:03:50
  • jdbc中class.forname的作用

    2023-04-13 00:56:18
  • 【MyBatis源码全面解析】MyBatis一二级缓存介绍

    2023-02-25 23:57:12
  • Android 屏幕双击事件的捕获简单示例

    2022-08-30 11:02:55
  • spring security动态配置url权限的2种实现方法

    2021-06-25 15:31:12
  • .NET企业级项目中遇到的国际化问题和解决方法

    2022-12-03 08:18:06
  • Android Studio 一键生成Json实体类教程

    2023-05-19 20:13:39
  • C#实现进制转换

    2021-11-22 11:52:13
  • java虚拟机原理:Class字节码二进制文件分析

    2022-02-06 09:02:33
  • 解决 INSTALL FAILED CONFLICTING PROVIDER的问题方法

    2023-01-31 11:42:49
  • android安装后启动出错解决

    2021-10-31 12:13:26
  • asp之家 软件编程 m.aspxhome.com