前一段时间在掘金里看到有网友仿写了即刻APP的点赞效果,感觉很炫酷,刚好公司的项目中也用到了点赞功能,于是乎就自己动手撸了一个,在原来的基础上增加了一些配置属性。
先来看看效果图:
首先添加依赖:
compile 'com.huach:thumbsupview:1.0.0'
然后在layout中的使用:
.hch.thumbsuplib.ThumbsUpCountView
android:id="@+id/thumbs_view4"
android:layout_width="wrap_content"
android:layout_height="50dp"
app:layout_constraintLeft_toRightOf="@id/text4"
app:layout_constraintTop_toTopOf="@id/text4"
app:thumbsup_off_drawable="@mipmap/ic_zan_off" //取消点赞图标
app:thumbsup_on_drawable="@mipmap/ic_zan_on" //点赞图标
app:thumbsup_on_show_circle="false" //是否显示动态圆环
app:thumbsup_on_show_decoration="false" //是否显示手指上边的装饰
app:thumbsup_off_text_color="#999999" //取消点赞的文字颜色
app:thumbsup_on_text_color="#F95C39" //点赞的文字颜色
/>
使用没什么可说的,配置参数注释也都写的很清楚,如果觉得还不能满足项目需求,大家可以下载源码修改 https://github.com/469412882/ThumbsUpView
首先我们观察这个效果的组成部分:
1、左侧拇指的动画,其中包括拇指的缩放、圆环的扩散、拇指上边三撇的动画
2、右侧的文字动画
所以为了左右效果的解耦,这里我选择定义三个view来实现这个效果,1、左侧view;2、右侧view;3、自定义LinearLayout来包裹这两个view。
左边的三个效果其实可以用一个属性动画就可以实现,拇指的缩放可以通过drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) 这个方法,不断的去改变bitmap的目标绘制区域(第三个参数)来实现。圆环和上边的动画可以通过维护一个mCirclePath,然后用canvas.clipPath(mCirclePath);来实现。
关键代码:
/**
* 执行动画
*/
private void runAnim() {
float[] scaleLevel;
/* 点赞和取消点赞的缩放比例变化 */
if (isThumbsUpOn) {
scaleLevel = new float[] { 0.8f, 1.2f, 1f };
} else {
scaleLevel = new float[] { 1f, 0.8f, 1f };
}
ValueAnimator animator = ValueAnimator.ofFloat(scaleLevel);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mFraction = animation.getAnimatedFraction();
float value = (float) animation.getAnimatedValue();
scaleThumbsRect(value);
postInvalidate();
}
});
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
mCirclePath.reset();
postInvalidate();
}
});
animator.setDuration(mDuration);
animator.start();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (isThumbsUpOn) {
canvas.save();
if (!mCirclePath.isEmpty()) {
if (mShowCircle) {
canvas.drawPath(mCirclePath, mCirclePaint);
}
canvas.clipPath(mCirclePath);
}
canvas.drawBitmap(thumbsUpOn, mThumbsRectSrc, mThumbsRectSrcDstReal, mBitmapPaint);
if (mShowDecoration) {
canvas.drawBitmap(thumbsUpDecoration, mDecorationRectSrc, mDecorationRectDst, mBitmapPaint);
}
canvas.restore();
} else {
canvas.drawBitmap(thumbsUpOff, mThumbsRectSrc, mThumbsRectSrcDstReal, mBitmapPaint);
}
}
代码很简单,没什么可讲的。缩放的比例可以看个人喜好去修改,圆环是根据mFraction 属性来计算出来的。
实现右边的文字效果需要做三件事:
1、根据当前的数字和变化后的数字比较得出需要变化的文字和不变的文字
2、变化的文字是要向上滑动的还是向下
3、文字是变亮的还是变暗的
数字的比较很容易能实现,关键是文字滑动的动画,我这里通过维护一个变量来判断要往上滑动还是往下:
offYBaseline = mCount > mOldCount ? 1 : -1;
1代表往上,-1代表往下,通过属性动画来改变offsetYProgress ;在onDraw中计算偏移量:
float offset = mPaint.getTextSize() * offsetYProgress;
canvas.drawText(mTextCount[1], getPaddingLeft(), mTextCount[1].length(), startX, baseLineY - offset, mPaint);
还有一个效果是文字颜色的渐变,首先要根据是否点赞来确定颜色的起始颜色startColor,endColor,然后根据动画的执行进度mFraction去获取当前的颜色值,获取颜色值的方法:
/**
* 根据fraction值来计算当前的颜色。
*/
private int getCurrentColor(float fraction, int startColor, int endColor) {
int redCurrent;
int blueCurrent;
int greenCurrent;
int alphaCurrent;
int redStart = Color.red(startColor);
int blueStart = Color.blue(startColor);
int greenStart = Color.green(startColor);
int alphaStart = Color.alpha(startColor);
int redEnd = Color.red(endColor);
int blueEnd = Color.blue(endColor);
int greenEnd = Color.green(endColor);
int alphaEnd = Color.alpha(endColor);
int redDifference = redEnd - redStart;
int blueDifference = blueEnd - blueStart;
int greenDifference = greenEnd - greenStart;
int alphaDifference = alphaEnd - alphaStart;
redCurrent = (int) (redStart + fraction * redDifference);
blueCurrent = (int) (blueStart + fraction * blueDifference);
greenCurrent = (int) (greenStart + fraction * greenDifference);
alphaCurrent = (int) (alphaStart + fraction * alphaDifference);
return Color.argb(alphaCurrent, redCurrent, greenCurrent, blueCurrent);
}
把颜色拆分成A、R、G、B,根据差值和当前进度来计算。
到这这个点赞实现的关键点就结束了,希望喜欢的同学能star一下。
源码地址