贝塞尔曲线的应用(三)

综合技术 2018-05-21 阅读原文

仿直播点赞爱心动画

先看下实现效果

点的轨迹可以采用三阶贝塞尔曲线

image.png

关键点分别是

PointF startF = new PointF(totalWidth / 2, totalHeight);
PointF pointF1 = new PointF(new Random().nextInt(totalWidth), new Random().nextInt(totalHeight / 2) + totalHeight / 2);
PointF pointF2 = new PointF(new Random().nextInt(totalWidth), new Random().nextInt(totalHeight / 2));
PointF endF = new PointF(new Random().nextInt(totalWidth), 0);

我们可以在点击时在初始点new一个imageview,根据给出的点运用贝塞尔三阶公式绘制imageview的运动轨迹。

同样,我们需要自定义估值器给出坐标的转换方法

public class PointEvaluate implements TypeEvaluator {

    private PointF pointF1, pointF2;

    public PointEvaluate(PointF pointF1, PointF pointF2) {
        this.pointF1 = pointF1;
        this.pointF2 = pointF2;
    }

    @Override
    public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
        float x = (1 - fraction) * (1 - fraction) * (1 - fraction) * startValue.x
                + 3 * (1 - fraction) * (1 - fraction) * fraction * pointF1.x
                + 3 * (1 - fraction) * fraction * fraction * pointF2.x
                + fraction * fraction * fraction * endValue.x;

        float y = (1 - fraction) * (1 - fraction) * (1 - fraction) * startValue.y
                + 3 * (1 - fraction) * (1 - fraction) * fraction * pointF1.y
                + 3 * (1 - fraction) * fraction * fraction * pointF2.y
                + fraction * fraction * fraction * endValue.y;
        return new PointF(x, y);
    }
}

为了让点赞的爱心显示的更自然,可以添加上scale动画和alpha动画以及爱心上移到屏幕顶端是,渐渐隐藏。

public class PraiseView extends RelativeLayout {


    private Drawable[] drawables;
    private LayoutParams layoutParams;
    private Context context;
    private Paint paint;
    private Path path;
    private int totalWidth, totalHeight, praiseWidth, praiseHeight;

    public PraiseView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        init();
    }

    public void init() {
        setWillNotDraw(false);
        Drawable a = getResources().getDrawable(R.mipmap.praise01);
        Drawable b = getResources().getDrawable(R.mipmap.praise02);
        Drawable c = getResources().getDrawable(R.mipmap.praise03);
        Drawable d = getResources().getDrawable(R.mipmap.praise04);

        praiseWidth = a.getIntrinsicWidth();
        praiseHeight = a.getIntrinsicHeight();

        drawables = new Drawable[]{a, b, c, d};
        layoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);

        layoutParams.addRule(ALIGN_PARENT_BOTTOM);
        layoutParams.addRule(CENTER_HORIZONTAL);

        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(6);
        paint.setColor(Color.BLUE);

        path = new Path();

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        totalHeight = getMeasuredHeight();
        totalWidth = getMeasuredWidth();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawPath(path, paint);

    }

    public void addPraise() {
        final ImageView imageView = new ImageView(context);
        imageView.setImageDrawable(drawables[new Random().nextInt(4)]);
        addView(imageView, layoutParams);


        PointF startF = new PointF(totalWidth / 2, totalHeight);
        PointF pointF1 = new PointF(new Random().nextInt(totalWidth), new Random().nextInt(totalHeight / 2) + totalHeight / 2);
        PointF pointF2 = new PointF(new Random().nextInt(totalWidth), new Random().nextInt(totalHeight / 2));
        PointF endF = new PointF(new Random().nextInt(totalWidth), 0);

//        path.moveTo(startF.x, startF.y);
//        path.cubicTo(pointF1.x, pointF1.y, pointF2.x, pointF2.y, endF.x, endF.y);
//        invalidate();

        ValueAnimator valueAnimator = ValueAnimator.ofObject(new PointEvaluate(pointF1, pointF2), startF, endF);
        valueAnimator.setDuration(1000);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                PointF animatedValue = (PointF) animation.getAnimatedValue();
                imageView.setX(animatedValue.x);
                imageView.setY(animatedValue.y);
                imageView.setAlpha(1 - animation.getAnimatedFraction());

            }
        });

//        ObjectAnimator scaleX = ObjectAnimator.ofFloat(imageView, "scaleX", 0, 1);
//        ObjectAnimator scaleY = ObjectAnimator.ofFloat(imageView, "scaleY", 0, 1);
//        ObjectAnimator alpha = ObjectAnimator.ofFloat(imageView, "alpha", 0, 1);

        PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 0,1);
        PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 0,1);
        PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 0,1);

        ValueAnimator valueAnimator1 = ObjectAnimator.ofPropertyValuesHolder(scaleX, alpha, scaleY);

//        AnimatorSet animatorSet = new AnimatorSet();
//        animatorSet.playTogether(scaleX, scaleY, alpha);
//        animatorSet.setDuration(500);



        AnimatorSet totalSet = new AnimatorSet();
        totalSet.playTogether(valueAnimator1, valueAnimator);
        totalSet.start();
        totalSet.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                removeView(imageView);
            }
        });
    }
}

可以在动画结束后removeView掉刚刚生成的imageview

简书

责编内容by:简书阅读原文】。感谢您的支持!

您可能感兴趣的

Array-Out Of Bound Exception on Android i'm new to android and got stuck up in horizontal swipe. let me explain in deta...
Android audio and video do not play on the web vie... I am developing epub reader for Android devices. Audio and video doesn't play o...
Kotlin Android入门教程 为了赶时髦,我也试了一把 Kotlin :wink: 怎么开始学习Kotlin呢? 因为我是Android出身,所以我就选择AndroidStudio开...
Android 的进程间通信 Binder——Messenger的入门使用... 进程间通信系列 AIDL的入门使用 Messenger的入门使用 序言:Messenger是Google为我们封装好的简洁版的AIDL,当面...
依赖注入实现组件化 本文演示如何使用依赖注入的方式实现组件化,本文假设你对什么是组件化已有一定认识,并且使用过 dagger2。 本文所说的组件均是指业务组件,包括有 UI 的...