android点赞动画仿twritter,【点赞动画仿抖音】Android 自定义view动画--酷炫点赞动画...

先看效果

19a2e3e7b686

看起来复杂,但是我们可以分步实现,最后你会发现很简单。

【第一步】:画圆---不断放大的空心圆 -- CircleView

想要的效果是不断扩大的空心圆。

关于这点我们可以有多种思路:

1.画一个空心圆然后根据半径不断增大从而达到效果

2.画两个圆,外圆实心,内圆清除,从而给人一种这样的效果

实验了一下,第二种效果更好一点。

代码如下,很简单。

public class CircleView extends View {

private static final int CIRCLE_COLOR = 0xFFF85680;

private Bitmap tempBitmap;

private Canvas tempCanvas;

private Paint outerPaint = new Paint();

private Paint innerPaint = new Paint();

private int maxCircleSize;

private float outerCircleRadiusProgress=0f;

private float innerCircleRadiusProgress=0f;

public CircleView(Context context) {

super(context);

init();

}

private void init() {

//初始化画笔

//外圆画笔样式为填充

outerPaint.setStyle(Paint.Style.FILL);

outerPaint.setColor(CIRCLE_COLOR);

//内圆图像混合模式之清除图像

innerPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));

}

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

super.onSizeChanged(w, h, oldw, oldh);

maxCircleSize = w / 2;

tempBitmap = Bitmap.createBitmap(getWidth(), getWidth(), Bitmap.Config.ARGB_8888);

tempCanvas = new Canvas(tempBitmap);

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

tempCanvas.drawColor(0xffffff, PorterDuff.Mode.CLEAR);

//画外圆

tempCanvas.drawCircle(getWidth() / 2, getHeight() / 2, outerCircleRadiusProgress * maxCircleSize, outerPaint);

//画内圆

tempCanvas.drawCircle(getWidth() / 2, getHeight() / 2, innerCircleRadiusProgress * maxCircleSize, innerPaint);

canvas.drawBitmap(tempBitmap, 0, 0, null);

}

//对外暴露的属性,设置进度,让圆心动态变化。

public void setInnerCircleRadiusProgress(float innerCircleRadiusProgress) {

this.innerCircleRadiusProgress = innerCircleRadiusProgress;

postInvalidate();

}

public void setOuterCircleRadiusProgress(float outerCircleRadiusProgress) {

this.outerCircleRadiusProgress = outerCircleRadiusProgress;

postInvalidate();

}

}

【第二步】:画四周点的视图--DotsView

本质还是画圆,只不过重要的是确定各个圆的圆心位置

for (int i = 0; i < DOTS_COUNT; i++) {

int cX = (int) (centerX + currentRadius * Math.cos(i * DOTS_POSITION_ANGLE * Math.PI / 180));

int cY = (int) (centerY + currentRadius * Math.sin(i * DOTS_POSITION_ANGLE * Math.PI / 180));

canvas.drawCircle(cX, cY, currentDotSize,ciclePaint);

}

贴出整个类

public class DotsView extends View {

//粒子个数

private static final int DOTS_COUNT = 6;

//粒子位置角度

private static final int DOTS_POSITION_ANGLE = 360 / DOTS_COUNT;

private static final int DOTS_COLOR = 0xFFF85680;

private float currentProgress = 0f;

private int centerX;

private int centerY;

private float maxDotSize;

private Paint dotsCiclePaint=new Paint();

private float currentRadius = 0;

private float currentDotSize = 0;

private Paint ciclePaint=new Paint();

private float maxDotsRadius;

public DotsView(Context context) {

super(context);

init();

}

public DotsView(Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

init();

}

private void init() {

ciclePaint.setStyle(Paint.Style.FILL);

ciclePaint.setColor(DOTS_COLOR);

}

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

super.onSizeChanged(w, h, oldw, oldh);

centerX = w / 2;

centerY = h / 2;

//粒子半径

maxDotSize = 4;

//最大半径

maxDotsRadius= w/2 - maxDotSize * 4;

}

@Override

protected void onDraw(Canvas canvas) {

drawOuterDotsFrame(canvas);

}

private void drawOuterDotsFrame(Canvas canvas) {

for (int i = 0; i < DOTS_COUNT; i++) {

int cX = (int) (centerX + currentRadius * Math.cos(i * DOTS_POSITION_ANGLE * Math.PI / 180));

int cY = (int) (centerY + currentRadius * Math.sin(i * DOTS_POSITION_ANGLE * Math.PI / 180));

canvas.drawCircle(cX, cY, currentDotSize,ciclePaint);

}

}

public void setCurrentProgress(float currentProgress) {

this.currentProgress = currentProgress;

updateOuterDotsPosition();

postInvalidate();

}

private void updateOuterDotsPosition() {

if (currentProgress < 0.3f) {

this.currentRadius = (float) mapValueFromRangeToRange(currentProgress, 0.0f, 0.3f, 0, maxDotsRadius * 0.8f);

} else {

this.currentRadius = (float) mapValueFromRangeToRange(currentProgress, 0.3f, 1f, 0.8f * maxDotsRadius, maxDotsRadius);

}

if (currentProgress < 0.7) {

this.currentDotSize = maxDotSize;

} else {

this.currentDotSize = (float) mapValueFromRangeToRange(currentProgress, 0.7f, 1f, maxDotSize, 0);

}

}

public static double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) {

return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow));

}

}

【第三步】:写一个LikeButtonView 把动画组合起来

view_like_button.xml

android:layout_width="wrap_content">

android:id="@+id/vDotsView"

android:layout_width="70dp"

android:layout_height="70dp"

android:layout_gravity="center"/>

android:id="@+id/vCircle"

android:layout_width="40dp"

android:layout_height="40dp"

android:layout_gravity="center"

/>

android:id="@+id/ivLike"

android:layout_width="35dp"

android:layout_height="35dp"

android:layout_gravity="center"

android:src="@drawable/like_select"/>

public class LikeAnimationView extends FrameLayout {

private static final DecelerateInterpolator DECCELERATE_INTERPOLATOR = new DecelerateInterpolator();

private static final AccelerateDecelerateInterpolator ACCELERATE_DECELERATE_INTERPOLATOR = new AccelerateDecelerateInterpolator();

private static final OvershootInterpolator OVERSHOOT_INTERPOLATOR = new OvershootInterpolator(4);

private boolean isChecked=true;

private ImageView ivLike;

private DotsView vDotsView;

private CircleView vCircleView;

private AnimatorSet animatorSet;

public LikeAnimationView(@NonNull Context context) {

super(context);

init();

}

public LikeAnimationView(@NonNull Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

init();

}

public LikeAnimationView(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {

super(context, attrs, defStyleAttr);

init();

}

private void init() {

LayoutInflater.from(getContext()).inflate(R.layout.view_like_button, this, true);

ivLike= (ImageView) findViewById(R.id.ivLike);

vCircleView= (CircleView) findViewById(R.id.vCircle);

vDotsView= (com.animation.collects.heart.view.DotsView) findViewById(R.id.vDotsView);

}

public void start(){

ivLike.setImageResource(R.drawable.like_select);

ivLike.setEnabled(false);

ivLike.animate().cancel();

ivLike.setScaleX(0);

ivLike.setScaleY(0);

vCircleView.setInnerCircleRadiusProgress(0);

vCircleView.setOuterCircleRadiusProgress(0);

vDotsView.setCurrentProgress(0);

animatorSet = new AnimatorSet();

ObjectAnimator outerCircleAnimator = ObjectAnimator.ofFloat

(vCircleView, "outerCircleRadiusProgress", 0f, 1f);

outerCircleAnimator.setDuration(550);

outerCircleAnimator.setStartDelay(0);

outerCircleAnimator.setInterpolator(DECCELERATE_INTERPOLATOR);

//目标属性的属性名、初始值或结束值

ObjectAnimator innerCircleAnimator = ObjectAnimator.ofFloat(vCircleView, "innerCircleRadiusProgress", 0f, 1f);

innerCircleAnimator.setDuration(650);

innerCircleAnimator.setStartDelay(0);

innerCircleAnimator.setInterpolator(DECCELERATE_INTERPOLATOR);

ObjectAnimator starScaleYAnimator = ObjectAnimator.ofFloat(ivLike, ImageView.SCALE_Y, 0.2f, 1f);

starScaleYAnimator.setDuration(550);

starScaleYAnimator.setStartDelay(0);

starScaleYAnimator.setInterpolator(OVERSHOOT_INTERPOLATOR);

ObjectAnimator starScaleXAnimator = ObjectAnimator.ofFloat(ivLike, ImageView.SCALE_X, 0.2f, 1f);

starScaleXAnimator.setDuration(550);

starScaleXAnimator.setStartDelay(0);

starScaleXAnimator.setInterpolator(OVERSHOOT_INTERPOLATOR);

ObjectAnimator dotsAnimator = ObjectAnimator.ofFloat(vDotsView, "currentProgress", 0, 1f);

dotsAnimator.setDuration(850);

dotsAnimator.setStartDelay(100);

dotsAnimator.setInterpolator(ACCELERATE_DECELERATE_INTERPOLATOR);

animatorSet.playTogether(

outerCircleAnimator,

innerCircleAnimator,

starScaleYAnimator,

starScaleXAnimator,

dotsAnimator

);

animatorSet.addListener(new AnimatorListenerAdapter() {

@Override

public void onAnimationEnd(Animator animation) {

super.onAnimationEnd(animation);

ivLike.setEnabled(true);

}

});

animatorSet.start();

}

}

【最后】

得到LikeAnimationView,这里暴露一个start的方法,在需要的地方调用即可。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值