Android点赞动画 Android实现简单点赞动画
碧云天丶 人气:2想了解Android实现简单点赞动画的相关内容吗,碧云天丶在本文为您仔细讲解Android点赞动画的相关知识和一些Code实例,欢迎阅读和指正,我们先划重点:Android,点赞,下面大家一起来学习吧。
思路
1、找到Activity中DecorView的RootView
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) }
效果
贝塞尔动画点赞效果
思路其实差不多, 具体看代码
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() }
效果
加载全部内容