华域联盟 Andriod Android实现简单点赞动画

Android实现简单点赞动画

本文实例为大家分享了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)
}

效果

贝塞尔动画点赞效果

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

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://www.cnhackhy.com/109623.htm

本文来自网络,不代表华域联盟立场,转载请注明出处。

作者: sterben

Android AlertDialog六种创建方式案例详解

发表回复

联系我们

联系我们

2551209778

在线咨询: QQ交谈

邮箱: [email protected]

工作时间:周一至周五,9:00-17:30,节假日休息

关注微信
微信扫一扫关注我们

微信扫一扫关注我们