安卓Android 直播点赞爱心特效,计时器

2021年9月17日 12点热度 0条评论 来源: Mr_Liangxiaobai

 

点赞特效,上图:

首先忽略这画质和抠脚的交互效果,首先需求就是 实现类似抖音的点赞效果 飘小心心的效果,UI的方案是做成了gif图,但是这种东西做成gif太low了,于是就有了想法,这边记录一下:

首先 图形是随机产生,这个不多说,ui的图片 然后点赞随机飘爱心的效果要怎么实现呢,想到的是 Android 自定义属性动画 ,那就用这个方式来实现吧,用自定义view的方式实现它,实现如下:

(爱心图标文件来源:IconFont  阿里巴巴矢量图标库 )

(源码下载地址在最后面)

你好sao啊!

 

 

package com.dpdp.base_moudle.weight;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.PointF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;

import com.dpdp.base_moudle.R;

import java.util.ArrayList;
import java.util.Random;

/**
 * Created by ldp.
 * <p>
 * Date: 2021-02-23
 * <p>
 * Summary: 点赞爱心动画
 * <p>
 * 固定宽高
 * <p>
 * 包含一个子view 或者没有 要放在最下面 动效爱心往上飘
 * <p>
 * @see #setLikeDrawables(int...) 设置 对应的 图片
 * @see #clickLikeView() 点击调用 开始动画 点一次出一个
 * @see #autoPlayClickView(int, boolean) 自动播放动画
 * @see #stopAutoPlay() 停止自动播放
 * @see #release() 释放资源 退出时调用
 */
public class FloatLikeView extends FrameLayout {

    private ArrayList<Drawable> mLikeDrawables;// 点赞的drawable集合
    private Random mRandom; //产生随机数来产生随机爱心
    private final Context context;
    private int mLikePicWidth = 0;// 爱心的 view 宽
    private int mLikePicHeight = 0;// 爱心的 view 高
    private LayoutParams mLikePicLayoutParams;// 布局参数
    private int mLikePicBottomMargin = 0;// 爱心出现位置距离底部
    private int mChildHeight = 0;// 如果底部设置了一个 view 爱心会在其上面
    private int mWidth;// 此布局view 宽
    private int mHeight;// 此布局view 高
    private AnimatorSet animator;// 爱心动画

    public FloatLikeView(@NonNull Context context) {
        this(context, null);
    }

    public FloatLikeView(@NonNull Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public FloatLikeView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
        init();
    }

    private void init() {
        // 存放 要显示的 效果
        mLikeDrawables = new ArrayList<>();
        // 设置一个默认的爱心
        mLikeDrawables.add(ContextCompat.getDrawable(context, R.drawable.ui_default_heart));
        // 产生随机数 随机选择 出现的图形
        mRandom = new Random();
    }

    /**
     * 设置 动画飘动的资源文件
     */
    public void setLikeDrawables(int... drawableIds) {
        if (drawableIds != null && drawableIds.length > 0) {
            mLikeDrawables.clear();
            for (int drawableId : drawableIds) {
                mLikeDrawables.add(ContextCompat.getDrawable(context, drawableId));
            }
        }
    }

    private ValueAnimator valueAnimator;

    /**
     * 自动 播放 飘爱心 动画 利用属性动画 进行3秒的
     * <p>
     * 设置了最大 30 个 看情况自己设置好吧 太多了不好看
     *
     * @param likeCounts 飘心的数量
     * @param isRepeat   是否重复播放
     *                   停止播放   {@link #stopAutoPlay()}
     */
    public void autoPlayClickView(int likeCounts, boolean isRepeat) {
        // 重复调用 则取消上次的重新开始
        if (valueAnimator != null) {
            valueAnimator.cancel();
            valueAnimator.removeAllUpdateListeners();
            valueAnimator = null;
        }
        valueAnimator = ValueAnimator.ofInt(0, Math.min(likeCounts, 30));//30
        valueAnimator.setDuration(3000);
        valueAnimator.setInterpolator(new LinearInterpolator());
        // 是否 开启循环播放 -====
        valueAnimator.setRepeatCount(isRepeat ? ValueAnimator.INFINITE : 1);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            int lastValue = 0;

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int animatedValue = ((int) animation.getAnimatedValue());
                // 利用 动画的更新回调 相当于一个定时效果 但是要注意 会有多次相同的回调 要判断一下
                if (animatedValue == lastValue) return;
                // 手动调用一次 相当于点击一次 出一个爱心效果
                clickLikeView();
                // 记录上次的值
                lastValue = animatedValue;
            }
        });
        valueAnimator.start();
    }

    /**
     * 停止自动播放
     * <p>
     * {@link #autoPlayClickView(int, boolean)} 自动播放
     */
    public void stopAutoPlay() {
        if (valueAnimator != null) {
            valueAnimator.cancel();
            valueAnimator.removeAllUpdateListeners();
        }
    }

    /**
     * 退出时 释放资源
     */
    public void release() {
        stopAutoPlay();
        if (animator != null) {
            animator.cancel();
            animator.removeAllListeners();
        }
    }

    /**
     * 点击调用 产生动效 调用一次 产生一个爱心飘动效果
     */
    public void clickLikeView() {

        if (mLikePicWidth == 0 || mLikePicHeight == 0 || mLikePicLayoutParams == null) {
            // 获取 点赞的 view 尺寸 ,这边定一个 统一尺寸
            mLikePicWidth = mLikeDrawables.get(0).getIntrinsicWidth();
            mLikePicHeight = mLikeDrawables.get(0).getIntrinsicHeight();

            // 指定爱心出现的位置
            mLikePicLayoutParams = new LayoutParams(mLikePicWidth, mLikePicHeight);
            // 位置在底部的中间
            mLikePicLayoutParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
            // 如果底部有一个 childView 则会在其上方 飘爱心
            mLikePicLayoutParams.bottomMargin = mLikePicBottomMargin;
        }

        ImageView likeIv = new ImageView(context);
        likeIv.setImageDrawable(mLikeDrawables.get(mRandom.nextInt(mLikeDrawables.size())));
        likeIv.setLayoutParams(mLikePicLayoutParams);
        addView(likeIv);
        addAnimationStart(likeIv);
    }


    /**
     * 飘爱心动画 主要逻辑
     */
    private void addAnimationStart(ImageView likeIv) {
        //----------------------------------- 出现 的动画-----------------------------------
        ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(likeIv, "alpha", 0.5f, 1f);
        ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(likeIv, "scaleX", 0.6f, 1f);
        ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(likeIv, "scaleY", 0.6f, 1f);
        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.playTogether(alphaAnimator, scaleXAnimator, scaleYAnimator);
        animatorSet.setDuration(200);
        animatorSet.setTarget(likeIv);

        //------------------------ 路径移动动画  基于 三阶贝塞尔曲线-------------------------
        PathEvaluator pathEvaluator = new PathEvaluator(getControlPointF(1), getControlPointF(2));
        // 设置 起点
        PointF startPointF = new PointF((float) (mWidth - mLikePicWidth) / 2, mHeight - mLikePicBottomMargin - mLikePicHeight);
        // 设置 终点
        PointF endPointF = new PointF((float) mWidth / 2 + (mRandom.nextBoolean() ? 1 : -1) * mRandom.nextInt(100), 0);
        // 自定义 属性动画 利用贝塞尔曲线 计算路径上的各个点的位置
        ValueAnimator valueAnimator = ValueAnimator.ofObject(pathEvaluator, startPointF, endPointF);
        valueAnimator.setDuration(3000);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                if (likeIv == null) return;
                // 根据各个点的位置 改变 view 的位置
                PointF pointF = (PointF) animation.getAnimatedValue();
                likeIv.setX(pointF.x);
                likeIv.setY(pointF.y);
                // 根据 动画的进度 设置透明度
                likeIv.setAlpha(1f - animation.getAnimatedFraction());
            }
        });
        valueAnimator.setTarget(likeIv);

        animator = new AnimatorSet();
        animator.setTarget(likeIv);
        // 动画顺序播放
        animator.playSequentially(animatorSet, valueAnimator);
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                // 动画结束 移除添加的 view
                // ~!!!
                // ~!!!
                // ~!!!
                removeView(likeIv);
            }
        });
        animator.start();

    }

    /**
     * 随机产生 三阶贝赛尔曲线 中间两个控制点
     *
     * @param value 控制点
     */
    private PointF getControlPointF(int value) {
        PointF pointF = new PointF();
        pointF.x = (float) mWidth / 2 - mRandom.nextInt(100);
        pointF.y = mRandom.nextInt((mHeight - mLikePicBottomMargin - mLikePicHeight) / value);
        return pointF;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int childCount = getChildCount();

        // 包含一个子view 或者没有 要放在最下面
        if (mChildHeight == 0 && childCount > 0) {
            View child = getChildAt(0);
            measureChild(child, widthMeasureSpec, heightMeasureSpec);
            mChildHeight = child.getMeasuredHeight();
            mLikePicBottomMargin = mChildHeight;
        }

        mHeight = getMeasuredHeight();
        mWidth = getMeasuredWidth();
    }

    private static class PathEvaluator implements TypeEvaluator<PointF> {

        private final PointF point01;
        private final PointF point02;

        public PathEvaluator(PointF point01, PointF point02) {
            this.point01 = point01;
            this.point02 = point02;
        }

        @Override
        public PointF evaluate(float fraction, PointF startValue, PointF endValue) {

            float change = 1.0f - fraction;
            PointF pointF = new PointF();

            // 三阶贝塞儿曲线
            pointF.x = (float) Math.pow(change, 3) * startValue.x
                    + 3 * (float) Math.pow(change, 2) * fraction * point01.x
                    + 3 * change * (float) Math.pow(fraction, 2) * point02.x
                    + (float) Math.pow(fraction, 3) * endValue.x;
            pointF.y = (float) Math.pow(change, 3) * startValue.y
                    + 3 * (float) Math.pow(change, 2) * fraction * point01.y
                    + 3 * change * fraction * fraction * point02.y
                    + (float) Math.pow(fraction, 3) * endValue.y;

            return pointF;
        }
    }


}

使用方法:

    <com.dpdp.base_moudle.weight.FloatLikeView
        android:id="@+id/like_btn_01"
        android:layout_width="100dp"
        android:layout_height="400dp">

        <Button
            android:id="@+id/praise_01"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom|center_horizontal"
            android:text="点一次出一次"
            android:textSize="12sp" />

    </com.dpdp.base_moudle.weight.FloatLikeView>
        // 设置爱心 文件
        layoutBinding.likeBtn01.setLikeDrawables(R.drawable.heart_01, R.drawable.heart_02, R.drawable.heart_03,
                R.drawable.heart_04, R.drawable.heart_05, R.drawable.heart_06);
        layoutBinding.praise01.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 爱心单个出现
                layoutBinding.likeBtn01.clickLikeView();
            }
        });

        layoutBinding.praise02.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 爱心动画自动播放
                layoutBinding.likeBtn01.autoPlayClickView(20, true);
                //爱心播放动画停止 
                //layoutBinding.likeBtn01.stopAutoPlay();
            }
        });
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        //退出时销毁 防止动画还没播放完就退出出现问题
        layoutBinding.likeBtn01.release();
    }

java 完整代码放在最后

接下来是前面那个计时器 ,记录一段时间点赞的次数然后 发送给服务端 如果点击一下 发送一次,接口压力太大,所以考虑过段时间提交一次,于是乎就有了比较奇怪的交互。 

 

 

 

 实现逻辑:

package com.dpdp.base_moudle;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.animation.AccelerateInterpolator;

import androidx.annotation.Keep;
import androidx.annotation.Nullable;


/**
 * Created by ldp.
 * <p>
 * Date: 2021-03-05
 * <p>
 * Summary: 点赞计数器 进度
 * 
 * @see #firstClick() 可以用于 第一次 点击出现 不进行缩放 按照需要来
 * @see #release() 释放资源
 * @see #setLikeClickCallback(LikeClickCallback) 回调 点击次数 
 */
public class LiveClickLikeView extends View implements View.OnClickListener {

    private int mWidth;// View的宽度
    private int mHeight;// View的高度
    private Paint bgPaint;// 背景画笔
    private RectF rect;// 圆环内切圆矩形
    private Paint bgArcPaint;// 圆环画笔
    private Paint progressArcPaint;// 进度画笔
    private Paint textPaint; // 中间文字画笔
    private int angle; // 绘制角度
    private int defaultSize = 100; // 默认一个最大尺寸
    private int clickCounts = 0;// 点击数
    private AnimatorSet animatorSet; // 动画集合
    private int bgPaintColor;// 圆形 背景色
    private int progressColor;// 进度条的颜色
    private int textColor; // 文字的颜色
    private int textSize;// 文字的 大小
    private int progressWidth; // 进度条宽度
    private ObjectAnimator animator; // 第一次显示出来大小不改变只有进度更新的动画

    public LiveClickLikeView(Context context) {
        this(context, null);
    }

    public LiveClickLikeView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public LiveClickLikeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        if (attrs != null) {
            TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.LiveClickLikeView);
            bgPaintColor = attributes.getColor(R.styleable.LiveClickLikeView_like_click_bg_circle_color, Color.BLACK);
            progressColor = attributes.getColor(R.styleable.LiveClickLikeView_like_click_progress_color, Color.BLUE);
            textColor = attributes.getColor(R.styleable.LiveClickLikeView_like_click_text_color, Color.WHITE);
            textSize = attributes.getDimensionPixelSize(R.styleable.LiveClickLikeView_like_click_text_size, 20);
            progressWidth = attributes.getDimensionPixelSize(R.styleable.LiveClickLikeView_like_click_progress_width, 10);
            attributes.recycle();
        }
        initPaint();
        setOnClickListener(this);
    }

    private void initPaint() {
        bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        bgPaint.setColor(bgPaintColor);
        bgPaint.setStyle(Paint.Style.FILL);

        rect = new RectF();

        bgArcPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        bgArcPaint.setColor(progressColor);
        bgArcPaint.setStyle(Paint.Style.STROKE);
        bgArcPaint.setStrokeWidth(progressWidth);

        progressArcPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        progressArcPaint.setColor(bgPaintColor);
        progressArcPaint.setStyle(Paint.Style.STROKE);
        progressArcPaint.setStrokeWidth(progressWidth);

        textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        textPaint.setColor(textColor);
        textPaint.setStyle(Paint.Style.FILL);
        textPaint.setTextSize(textSize);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        // 测量宽高
        setMeasuredDimension(measureSize(widthMeasureSpec), measureSize(heightMeasureSpec));
        // 获取宽高
        mHeight = getMeasuredHeight();
        mWidth = getMeasuredWidth();

        // 根据测量的宽高 计算 圆环进度条的 内切圆的矩形的宽高
        rect.left = progressWidth >> 1;// 等价于 progressWidth/2
        rect.right = mWidth - (progressWidth >> 1);
        rect.top = progressWidth >> 1;
        rect.bottom = mHeight - (progressWidth >> 1);
    }

    private int measureSize(int measureSpec) {
        int result = 0;
        int mode = MeasureSpec.getMode(measureSpec);
        int size = MeasureSpec.getSize(measureSpec);
        if (mode == MeasureSpec.EXACTLY) {
            // //当specMode = EXACTLY时,精确值模式,即当我们在布局文件中为View指定了具体的大小
            result = size;
        } else {
            result = defaultSize;
            if (mode == MeasureSpec.AT_MOST) {
                result = Math.min(defaultSize, size);
            }
        }
        return result;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 背景
        canvas.drawCircle(mWidth >> 1, mHeight >> 1, mWidth >> 1, bgPaint);
        // 圆环
        canvas.drawArc(rect, -90, 360, false, bgArcPaint);
        // 叠加背景色一样的圆环 进度条消失动画的原理
        canvas.drawArc(rect, -90, angle, false, progressArcPaint);
        // 测量文字宽高
        float textWidth = textPaint.measureText("x " + clickCounts);
        Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
        float textHeight = fontMetrics.bottom - fontMetrics.top;
        //绘制文字  宽度超过 view宽度的 4/5,按0.8比例自动进行缩放
        while (textWidth > mWidth * 0.8f) {
            textSize = ((int) (textSize * 0.8f));
            textPaint.setTextSize(textSize);
            textWidth = textPaint.measureText("x " + clickCounts);
            textHeight = fontMetrics.bottom - fontMetrics.top;
        }
        canvas.drawText("x " + clickCounts, (mWidth - textWidth) / 2, (mHeight >> 1) + textHeight / 4, textPaint);
    }

    @Keep
    public void setAngle(int angle) {
        // 改变角度 不停地重绘 形成进度条效果
        this.angle = angle;
        invalidate();
    }

    // 区分用户频繁点击触发结束
    private boolean isUserCancel = false;

    @Override
    public void onClick(View v) {
        // 取消第一次的动画
        if (animator != null && animator.isRunning()) {
            animator.removeAllListeners();
            animator.cancel();
        }
        // 取消未完成的动画
        if (animatorSet != null && animatorSet.isRunning()) {
            isUserCancel = true;
            animatorSet.removeAllListeners();
            animatorSet.cancel();
        }
        //增加一次点击次数
        clickCounts++;
        // x缩放动画
        ObjectAnimator scaleX = ObjectAnimator.ofFloat(this, "scaleX", 1f, 1.5f, 1f);
        // y缩放动画
        ObjectAnimator scaleY = ObjectAnimator.ofFloat(this, "scaleY", 1f, 1.5f, 1f);
        // 角度 动画 改变角度 形成进度条动画
        ObjectAnimator angle = ObjectAnimator.ofInt(this, "angle", 0, 360);
        // 进度条动画持续5秒
        angle.setDuration(5000);
        // 动画监听
        angle.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                // 如果是用户再次点击 取消上次动画,播放新的动画,上个动画结束不进行操作,
                // 只有动画自己执行完成才会回调 统计一次点赞次数
                if (isUserCancel) return;

                if (likeClickCallback != null) {
                    // 回调5秒内的点击次数
                    likeClickCallback.likeCountsCallback(clickCounts);
                    // 重置 点击次数
                    clickCounts = 0;
                }
            }
        });
        animatorSet = new AnimatorSet();
        // 组合动画
        animatorSet.playTogether(scaleX, scaleY, angle);
        animatorSet.setTarget(this);
        // 差值器
        animatorSet.setInterpolator(new AccelerateInterpolator());
        // 开始播放动画
        animatorSet.start();
        isUserCancel = false;
    }

    /**
     * 第一次点击的动画 只是进度条 不进行缩放
     */
    public void firstClick() {
        clickCounts++;
        animator = ObjectAnimator.ofInt(this, "angle", 0, 360);
        animator.setDuration(5000);
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                if (isUserCancel) return;
                Log.e("animation", "1 auto end " + clickCounts);
                if (likeClickCallback != null) {
                    likeClickCallback.likeCountsCallback(clickCounts);
                    clickCounts = 0;
                }
            }
        });
        animator.start();
    }

    /**
     * 结束动画释放资源
     */
    public void release() {
        if (animator != null) {
            animator.removeAllListeners();
            animator.cancel();
            animator = null;
        }
        if (animatorSet != null) {
            animatorSet.removeAllListeners();
            animatorSet.cancel();
            animatorSet = null;
        }
    }

    private LikeClickCallback likeClickCallback;

    public void setLikeClickCallback(LikeClickCallback likeClickCallback) {
        this.likeClickCallback = likeClickCallback;
    }

    public interface LikeClickCallback {
        void likeCountsCallback(int clickLikeCounts);
    }

}

    <declare-styleable name="LiveClickLikeView">
         <!-- 进度条颜色-->
        <attr name="like_click_progress_color" format="color" />
        <!-- 进度条宽度-->
        <attr name="like_click_progress_width" format="dimension" />
        <!-- 圆形背景颜色-->
        <attr name="like_click_bg_circle_color" format="color" />
        <!-- 文字颜色-->
        <attr name="like_click_text_color" format="color" />
        <!-- 文字大小 会自动进行缩放 严格说是最大的文字大小-->
        <attr name="like_click_text_size" format="dimension" />
    </declare-styleable>

 

使用方法:


    <xxx.xxx(包名).LiveClickLikeView
        android:id="@+id/like"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:layout_marginTop="100dp"
        android:layout_marginBottom="60dp"
        android:visibility="gone"
        app:layout_constraintBottom_toTopOf="@+id/praise_02"
        app:layout_constraintLeft_toLeftOf="@+id/praise_02"
        app:layout_constraintRight_toRightOf="@+id/praise_02"
        app:like_click_bg_circle_color="@color/color_333333"
        app:like_click_progress_color="@android:color/holo_blue_light"
        app:like_click_progress_width="4dp"
        app:like_click_text_color="@android:color/white"
        app:like_click_text_size="20sp"
        tools:visibility="visible" />

        layoutBinding.calculateNumBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 第一次点击出现
                layoutBinding.like.setVisibility(View.VISIBLE);
                layoutBinding.like.firstClick();
            }
        });

        layoutBinding.like.setLikeClickCallback(new LiveClickLikeView.LikeClickCallback() {
            @Override
            public void likeCountsCallback(int clickLikeCounts) {
                // 点击回调
                ToastUtil.showMsg("点击了 " + clickLikeCounts + "  次");
            }
        });

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 及时结束动画
        layoutBinding.like.release();
    }

完整代码在最后

完整代码:布局解析用了 ViewBinding,提一句: Kotlin不用写finviewbyid的方式已经过时了,居然已经过时了!!! Google 推荐使用ViewBing !!!

package com.example.administrator.words;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;

import androidx.annotation.Nullable;

import com.dpdp.base_moudle.LiveClickLikeView;
import com.dpdp.base_moudle.base.ui.BaseActivity;
import com.dpdp.base_moudle.utils.ToastUtil;
import com.example.administrator.words.databinding.ActivityGoodTestLayoutBinding;

/**
 * Created by ldp.
 * <p>
 * Date: 2021-02-23
 * <p>
 * Summary:
 * <p>
 */
public class TestGoodActivity extends BaseActivity {

    private ActivityGoodTestLayoutBinding layoutBinding;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        layoutBinding = ActivityGoodTestLayoutBinding.inflate(LayoutInflater.from(this));
        setContentView(layoutBinding.getRoot());

        // 设置爱心 文件
        layoutBinding.likeBtn01.setLikeDrawables(R.drawable.heart_01, R.drawable.heart_02, R.drawable.heart_03,
                R.drawable.heart_04, R.drawable.heart_05, R.drawable.heart_06);
        layoutBinding.praise01.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 爱心单个出现
                layoutBinding.likeBtn01.clickLikeView();
            }
        });

        layoutBinding.praise02.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 爱心动画自动播放
                layoutBinding.likeBtn01.autoPlayClickView(20, true);
                //爱心播放动画停止
                //layoutBinding.likeBtn01.stopAutoPlay();
            }
        });

        layoutBinding.calculateNumBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 第一次点击出现
                layoutBinding.like.setVisibility(View.VISIBLE);
                layoutBinding.like.firstClick();
            }
        });

        layoutBinding.like.setLikeClickCallback(new LiveClickLikeView.LikeClickCallback() {
            @Override
            public void likeCountsCallback(int clickLikeCounts) {
                // 点击回调
                ToastUtil.showMsg("点击了 " + clickLikeCounts + "  次");
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        layoutBinding.likeBtn01.release();
        // 及时结束动画
        layoutBinding.like.release();
    }
}

 

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.dpdp.base_moudle.weight.FloatLikeView
        android:id="@+id/like_btn_01"
        android:layout_width="100dp"
        android:layout_height="400dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/praise_02">

        <Button
            android:id="@+id/praise_01"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom|center_horizontal"
            android:text="点一次出一次"
            android:textSize="12sp" />

    </com.dpdp.base_moudle.weight.FloatLikeView>


    <Button
        android:id="@+id/praise_02"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="6dp"
        android:text="自动播放点赞"
        android:textSize="12sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toRightOf="@+id/like_btn_01"
        app:layout_constraintRight_toRightOf="parent" />


    <com.dpdp.base_moudle.LiveClickLikeView
        android:id="@+id/like"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:layout_marginTop="100dp"
        android:layout_marginBottom="60dp"
        android:visibility="gone"
        app:layout_constraintBottom_toTopOf="@+id/praise_02"
        app:layout_constraintLeft_toLeftOf="@+id/praise_02"
        app:layout_constraintRight_toRightOf="@+id/praise_02"
        app:like_click_bg_circle_color="@color/color_333333"
        app:like_click_progress_color="@android:color/holo_blue_light"
        app:like_click_progress_width="4dp"
        app:like_click_text_color="@android:color/white"
        app:like_click_text_size="20sp"
        tools:visibility="visible" />

    <Button
        android:id="@+id/calculate_num_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="200dp"
        android:text="计数器"
        app:layout_constraintBottom_toTopOf="@+id/praise_02"
        app:layout_constraintLeft_toLeftOf="@+id/praise_02"
        app:layout_constraintRight_toRightOf="@+id/praise_02" />

</androidx.constraintlayout.widget.ConstraintLayout>

 

感谢您的拜读! 源代码地址:

1、github源码地址,谢谢您的支持!

2、CSDN免费下载地址

部分源码用kotlin进行修正编写,博客里面没有做修改,大同小异,加油,各位!

编辑于-------2021年3月15日14:52:15 

 

 

    原文作者:Mr_Liangxiaobai
    原文地址: https://blog.csdn.net/Mr_Liangxiaobai/article/details/114531518
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系管理员进行删除。