Android實現(xiàn)簡單點贊動畫
本文實例為大家分享了Android實現(xiàn)簡單點贊動畫的具體代碼,供大家參考,具體內(nèi)容如下
思路
1、找到Activity中DecorView的RootView
2、確定點贊控件位于屏幕中的坐標(biāo)值
3、將點贊效果View加入到RootView中, 給效果View添加自己想要的動畫效果.
4、重復(fù)點擊時候, 需要將效果View先移除掉再重新加入到RootView中.
代碼
/** * 普通點贊效果, 點擊控件后出現(xiàn)一個View上浮 */ public class ViewLikeUtils { public interface ViewLikeClickListener { /** * @param view 被點贊的按鈕 * @param toggle 開關(guān) * @param viewLikeUtils 工具類本身 */ void onClick(View view, boolean toggle, ViewLikeUtils viewLikeUtils); } // 被點擊的按鈕 private View mClickView; private View mAnimView; private ViewLikeClickListener mListener; private boolean toggle = false; // 點擊開關(guān)標(biāo)識 private int mX; // 距離屏幕左側(cè)距離 private int mY; // 距離屏幕頂端距離, 越往下數(shù)值越大 /** * @param mClickView 被點擊的View * @param mAnimView 點贊后, 向上浮動的View * @param mListener 被點擊的View,點擊后的回調(diào)事件. */ public ViewLikeUtils(View mClickView, View mAnimView, @NonNull ViewLikeClickListener mListener) { this.mClickView = mClickView; this.mAnimView = mAnimView; this.mListener = mListener; initListener(); } /** * 設(shè)置View的監(jiān)聽 */ 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的坐標(biāo) toggle = !toggle; if (mListener != null) { mListener.onClick(mClickView, toggle, ViewLikeUtils.this); } // mView.performClick(); } // 正常的OnClickListener將無法調(diào)用 return true; } }); } /** * 獲取View在屏幕中的坐標(biāo) */ 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 開關(guān) * @param viewLikeBesselUtils 工具類本身 */ void onClick(View view, boolean toggle, ViewLikeBesselUtils viewLikeBesselUtils); } // 被點擊的按鈕 private View mClickView; private View[] mAnimViews; private ViewLikeClickListener mListener; private boolean toggle = false; // 點擊開關(guān)標(biāo)識 private int mX; // 距離屏幕左側(cè)距離 private int mY; // 距離屏幕頂端距離, 越往下數(shù)值越大 private Random mRandom = new Random(); // 隨機數(shù) /** * @param mClickView 被點擊的View * @param mAnimViews 點贊后, 向上浮動的View數(shù)組 * @param mListener 被點擊的View,點擊后的回調(diào)事件. */ public ViewLikeBesselUtils(View mClickView, View[] mAnimViews, @NonNull ViewLikeClickListener mListener) { this.mClickView = mClickView; this.mAnimViews = mAnimViews; this.mListener = mListener; initListener(); } /** * 設(shè)置View的監(jiān)聽 */ 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的坐標(biāo) toggle = !toggle; if (mListener != null) { mListener.onClick(mClickView, toggle, ViewLikeBesselUtils.this); } // mView.performClick(); } // 正常的OnClickListener將無法調(diào)用 return true; } }); } /** * 獲取View在屏幕中的坐標(biāo) */ 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() }
效果
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android RecyclerView添加FootView和HeadView
這篇文章主要介紹了Android RecyclerView添加FootView和HeadView的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-10-10Android 高德地圖之poi搜索功能的實現(xiàn)代碼
這篇文章主要介紹了android 高德地圖之poi搜索功能的實現(xiàn)代碼,在實現(xiàn)此功能時遇到很多問題,在文章都給大家提到,需要的朋友可以參考下2017-08-08Android簡單創(chuàng)建一個Activity的方法
這篇文章主要介紹了Android簡單創(chuàng)建一個Activity的方法,結(jié)合圖文形式分析了Android創(chuàng)建Activity的具體步驟與實現(xiàn)技巧,需要的朋友可以參考下2016-04-04