アニメーション表示(コード領域)のためのベジエ曲線の導入とAndroid

public class MyView extends View {

    private Point controlPoint = new Point(200, 200); //控制点坐标
   
    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        Paint paint = new Paint();
        paint.setStyle(Paint.Style.STROKE);
        paint.setColor(Color.BLACK);
        paint.setStrokeWidth(10);//设置画笔风格

        Path path = new Path();
        path.moveTo(100, 500);
        path.quadTo(controlPoint.x, controlPoint.y, 700, 500);
        //绘制路径
        canvas.drawPath(path, paint);
        //绘制辅助点
        canvas.drawPoint(controlPoint.x,controlPoint.y,paint);

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_MOVE:
                controlPoint.x = (int) event.getX();
                controlPoint.y = (int) event.getY();
                invalidate();//得到手触摸屏幕的坐标
                break;
        }
        return true;
    }
}
public class MyView1 extends View {

    private Point controlPointOne = new Point(200, 200);
    private Point controlPointTwo = new Point(500, 200);

    private boolean isControlPointTwo ;

    private Paint paintBezier;
    private Paint paintLine;

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

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

    public MyView1(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        paintBezier = new Paint();
        paintBezier.setStyle(Paint.Style.STROKE);
        paintBezier.setColor(Color.BLACK);
        paintBezier.setStrokeWidth(10);


        paintLine = new Paint();
        paintLine.setStyle(Paint.Style.STROKE);
        paintLine.setColor(Color.RED);
        paintLine.setStrokeWidth(3);

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);


        Path path = new Path();
        path.moveTo(100, 500);
        path.cubicTo(controlPointOne.x, controlPointOne.y,controlPointTwo.x, controlPointTwo.y, 900, 500);
        //绘制路径
        canvas.drawPath(path, paintBezier);
        //绘制辅助点
        canvas.drawPoint(controlPointOne.x, controlPointOne.y, paintBezier);
        canvas.drawPoint(controlPointTwo.x, controlPointTwo.y, paintBezier);
        //绘制连线
//        canvas.drawLine(100, 500, controlPointOne.x, controlPointOne.y, paintLine);
//        canvas.drawLine(900, 500, controlPointOne.x, controlPointOne.y, paintLine);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_MOVE:
                if (isControlPointTwo){
                    controlPointOne.x = (int) event.getX();
                    controlPointOne.y = (int) event.getY();
                }else {
                    controlPointTwo.x = (int) event.getX();
                    controlPointTwo.y = (int) event.getY();
                }
                invalidate();
                break;
        }
        return true;
    }


    public boolean isControlPointTwo() {
        return isControlPointTwo;
    }

    public void setControlPointTwo(boolean controlPointTwo) {
        isControlPointTwo = controlPointTwo;
    }
}
public class LikeStar extends ViewGroup {
    private List<Drawable> mStarDrawable;
    private List<Interpolator> mInterpolators;
    private int mWidth;
    private int mHeight;
    //定义贝塞尔曲线的数据点和两个控制点
    private PointF mStartPoint, mEndPoint, mControllPointOne, mControllPointTwo;

   private Random random = new Random();

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

    public LikeStar(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public LikeStar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(final Context context) {
        mStarDrawable = new ArrayList<>();
        mInterpolators = new ArrayList<>();
        mStartPoint = new PointF();
        mEndPoint = new PointF();
        mControllPointOne = new PointF();
        mControllPointTwo = new PointF();

        //初始化图片资源
        mStarDrawable.add(getResources().getDrawable(R.mipmap.heart_red));
        mStarDrawable.add(getResources().getDrawable(R.mipmap.heart_blue));
        mStarDrawable.add(getResources().getDrawable(R.mipmap.heart_yellow));
        mStarDrawable.add(getResources().getDrawable(R.mipmap.heart_green));

        //初始化插补器
        mInterpolators.add(new LinearInterpolator());
        mInterpolators.add(new AccelerateDecelerateInterpolator());
        mInterpolators.add(new AccelerateInterpolator());
        mInterpolators.add(new DecelerateInterpolator());

        ImageView image_heard = new ImageView(context);
        image_heard.setImageDrawable(mStarDrawable.get(0));

        image_heard.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
                LayoutParams.WRAP_CONTENT));

        image_heard.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                //点击之后开始动画,添加红心到布局文件并开始动画
                final ImageView image_random = new ImageView(context);
                image_random.setImageDrawable(mStarDrawable.get(random.nextInt(4)));

                image_random.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
                        LayoutParams.WRAP_CONTENT));
                addView(image_random);

                invalidate();

                //开始做动画效果
                PointF endPointRandom = new PointF(random.nextInt(mWidth), mEndPoint.y);
   //             BezierTypeEvaluator bezierTypeEvaluator = new BezierTypeEvaluator(mControllPointOne, mControllPointTwo);
                BezierTypeEvaluator bezierTypeEvaluator = new BezierTypeEvaluator(new PointF( random.nextInt(mWidth ),random.nextInt(mHeight)), new PointF( random.nextInt(mWidth),random.nextInt(mHeight)));
                ValueAnimator valueAnimator = ValueAnimator.ofObject(bezierTypeEvaluator, mStartPoint, endPointRandom);
                valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        PointF pointF = (PointF) animation.getAnimatedValue();
                        image_random.setX(pointF.x);
                        image_random.setY(pointF.y);
                    }
                });

                valueAnimator.setDuration(2000);
                valueAnimator.start();

            }
        });

        addView(image_heard);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

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

        // 初始化各个点

        //借用第一个子view控件中的宽高
        View child = getChildAt(0);
        int childW = child.getMeasuredWidth();
        int childH = child.getMeasuredHeight();

        mStartPoint.x = (mWidth - childW) / 2;
        mStartPoint.y = mHeight - childH;
        mEndPoint.x = (mWidth - childW) / 2;
        mEndPoint.y = 0 - childH;

        mControllPointOne.x = random.nextInt(mWidth / 2);
        mControllPointOne.y = random.nextInt(mHeight / 2) + mHeight / 2;

        mControllPointTwo.x = random.nextInt(mWidth / 2) + mWidth / 2;
        mControllPointTwo.y = random.nextInt(mHeight / 2);

    }

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

        //获取view的宽高测量模式
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);

        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        //保存测量高度
        setMeasuredDimension(widthSize, heightSize);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        Log.i("zhangyubin", "l:" + l + ",t:" + t + ",r:" + r + ",b:" + b);
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            int childW = child.getMeasuredWidth();
            int childH = child.getMeasuredHeight();
            child.layout((mWidth - childW) / 2, (mHeight - childH), (mWidth - childW) / 2 + childW, mHeight);
        }
    }

//    /**
//     * 开始动画
//     */

    //向外提供方法,用于点击事件触发动画发生
    public void startRunning() {
        BezierTypeEvaluator bezierTypeEvaluator = new BezierTypeEvaluator(mControllPointOne, mControllPointTwo);
        ValueAnimator valueAnimator = ValueAnimator.ofObject(bezierTypeEvaluator, mStartPoint, mEndPoint);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
               PointF pointF = (PointF) animation.getAnimatedValue();
               getChildAt(0).setX(pointF.x);
               getChildAt(0).setY(pointF.y);
            }
       });

       valueAnimator.setDuration(3000);
        valueAnimator.start();
    }


    public class BezierTypeEvaluator implements TypeEvaluator<PointF> {
        private PointF mControllPoint1, mControllPoint2;

        public BezierTypeEvaluator(PointF mControllPointOne, PointF mControllPointTwo) {
            mControllPoint1 = mControllPointOne;
            mControllPoint2 = mControllPointTwo;
        }

        @Override
        public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
            PointF pointCur = new PointF();
            pointCur.x = mStartPoint.x * (1 - fraction) * (1 - fraction) * (1 - fraction) + 3
                    * mControllPoint1.x * fraction * (1 - fraction) * (1 - fraction) + 3
                    * mControllPoint2.x * (1 - fraction) * fraction * fraction + endValue.x * fraction * fraction * fraction;// 实时计算最新的点X坐标
            pointCur.y = mStartPoint.y * (1 - fraction) * (1 - fraction) * (1 - fraction) + 3
                    * mControllPoint1.y * fraction * (1 - fraction) * (1 - fraction) + 3
                    * mControllPoint2.y * (1 - fraction) * fraction * fraction + endValue.y * fraction * fraction * fraction;// 实时计算最新的点Y坐标
            return pointCur;
        }
    }

}

 

公開された37元の記事 ウォン称賛10 ビュー10000 +

おすすめ

転載: blog.csdn.net/OneLinee/article/details/81385916