点赞特效,上图:
首先忽略这画质和抠脚的交互效果,首先需求就是 实现类似抖音的点赞效果 飘小心心的效果,UI的方案是做成了gif图,但是这种东西做成gif太low了,于是就有了想法,这边记录一下:
首先 图形是随机产生,这个不多说,ui的图片 然后点赞随机飘爱心的效果要怎么实现呢,想到的是 Android 自定义属性动画 ,那就用这个方式来实现吧,用自定义view的方式实现它,实现如下:
你好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>
感谢您的拜读! 源代码地址:
部分源码用kotlin进行修正编写,博客里面没有做修改,大同小异,加油,各位!
编辑于-------2021年3月15日14:52:15