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

效果

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持Devmax。

Android实现简单点赞动画的更多相关文章

  1. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  2. html5 canvas合成海报所遇问题及解决方案总结

    这篇文章主要介绍了html5 canvas合成海报所遇问题及解决方案总结,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  3. Html5 video标签视频的最佳实践

    这篇文章主要介绍了Html5 video标签视频的最佳实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  4. HTML5在微信内置浏览器下右上角菜单的调整字体导致页面显示错乱的问题

    HTML5在微信内置浏览器下,在右上角菜单的调整字体导致页面显示错乱的问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧

  5. ios – containerURLForSecurityApplicationGroupIdentifier:在iPhone和Watch模拟器上给出不同的结果

    我使用默认的XCode模板创建了一个WatchKit应用程序.我向iOSTarget,WatchkitAppTarget和WatchkitAppExtensionTarget添加了应用程序组权利.(这是应用程序组名称:group.com.lombax.fiveminutes)然后,我尝试使用iOSApp和WatchKitExtension访问共享文件夹URL:延期:iOS应用:但是,测试NSURL

  6. Ionic – Splash Screen适用于iOS,但不适用于Android

    我有一个离子应用程序,其中使用CLI命令离子资源生成的启动画面和图标iOS版本与正在渲染的启动画面完美配合,但在Android版本中,只有在加载应用程序时才会显示白屏.我检查了config.xml文件,所有路径看起来都是正确的,生成的图像出现在相应的文件夹中.(我使用了splash.psd模板来生成它们.我错过了什么?这是config.xml文件供参考,我觉得我在这里做错了–解决方法在config.xml中添加以下键:它对我有用!

  7. ios – 无法启动iPhone模拟器

    /Library/Developer/CoreSimulator/Devices/530A44CB-5978-4926-9E91-E9DBD5BFB105/data/Containers/Bundle/Application/07612A5C-659D-4C04-ACD3-D211D2830E17/ProductName.app/ProductName然后,如果您在Xcode构建设置中选择标准体系结构并再次构建和运行,则会产生以下结果:dyld:lazysymbolbindingFailed:Symbol

  8. Xamarin iOS图像在Grid内部重叠

    heyo,所以在Xamarin我有一个使用并在其中包含一对,所有这些都包含在内.这在Xamarin.Android中看起来完全没问题,但是在Xamarin.iOS中,图像与标签重叠.我不确定它的区别是什么–为什么它在Xamarin.Android中看起来不错但在iOS中它的全部都不稳定?

  9. 在iOS上向后播放HTML5视频

    我试图在iPad上反向播放HTML5视频.HTML5元素包括一个名为playbackRate的属性,它允许以更快或更慢的速率或相反的方式播放视频.根据Apple’sdocumentation,iOS不支持此属性.通过每秒多次设置currentTime属性,可以反复播放,而无需使用playbackRate.这种方法适用于桌面Safari,但似乎在iOS设备上的搜索限制为每秒1次更新–在我的情况下太慢了.有没有办法在iOS设备上向后播放HTML5视频?解决方法iOS6Safari现在支持playbackRat

  10. 使用 Swift 语言编写 Android 应用入门

    Swift标准库可以编译安卓armv7的内核,这使得可以在安卓移动设备上执行Swift语句代码。做梦,虽然Swift编译器可以胜任在安卓设备上编译Swift代码并运行。这需要的不仅仅是用Swift标准库编写一个APP,更多的是你需要一些框架来搭建你的应用用户界面,以上这些Swift标准库不能提供。简单来说,构建在安卓设备上使用的Swiftstdlib需要libiconv和libicu。通过命令行执行以下命令:gitclonegit@github.com:SwiftAndroid/libiconv-libi

随机推荐

  1. Flutter 网络请求框架封装详解

    这篇文章主要介绍了Flutter 网络请求框架封装详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. Android单选按钮RadioButton的使用详解

    今天小编就为大家分享一篇关于Android单选按钮RadioButton的使用详解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧

  3. 解决android studio 打包发现generate signed apk 消失不见问题

    这篇文章主要介绍了解决android studio 打包发现generate signed apk 消失不见问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

  4. Android 实现自定义圆形listview功能的实例代码

    这篇文章主要介绍了Android 实现自定义圆形listview功能的实例代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  5. 详解Android studio 动态fragment的用法

    这篇文章主要介绍了Android studio 动态fragment的用法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  6. Android用RecyclerView实现图标拖拽排序以及增删管理

    这篇文章主要介绍了Android用RecyclerView实现图标拖拽排序以及增删管理的方法,帮助大家更好的理解和学习使用Android,感兴趣的朋友可以了解下

  7. Android notifyDataSetChanged() 动态更新ListView案例详解

    这篇文章主要介绍了Android notifyDataSetChanged() 动态更新ListView案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下

  8. Android自定义View实现弹幕效果

    这篇文章主要为大家详细介绍了Android自定义View实现弹幕效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  9. Android自定义View实现跟随手指移动

    这篇文章主要为大家详细介绍了Android自定义View实现跟随手指移动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. Android实现多点触摸操作

    这篇文章主要介绍了Android实现多点触摸操作,实现图片的放大、缩小和旋转等处理,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部