自定义贝塞尔曲线运动


先看下效果:


实现思路:

1:第一步绘制,利用Path 类 画出一条二阶贝塞尔曲线。

2:第二步记录曲线运动坐标点。模拟Path类 封装一个类MyPath,负责记录贝塞尔曲线各个控制点。

        3:将 绘制的曲线的坐标点 和 运动的坐标点 设为一致,自定义一个二阶 贝塞尔曲线估值器,

               并利用属性动画结合MyPath 工具类记录的坐标点,来控制View的坐标x,y.

              使view沿着曲线运动即可。

     第一步代码:绘制二阶贝塞尔曲线

package example.nzh.com.beisaier;

import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.LinearInterpolator;


public class PathView extends View {

    Path path;
    
    Paint paint;

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

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

    }

    public PathView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        init();
    }

    private void init() {
        paint = new Paint();
        paint.setColor(Color.BLUE);
        paint.setStrokeWidth(8);
        paint.setStyle(Paint.Style.STROKE);

        path = new Path();
       
    }


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

        //定位到起始点
        path.moveTo(200, 200);
        //二阶贝塞尔曲线
        //参数:支点,终点的坐标(相对于起始点 绝对坐标绘制)
        path.quadTo(500, 700, 600, 200);
        //默认接着上一个曲线的结束点
//        path.quadTo(...);
        //相对于最后一个点 相对坐标绘制(300,100)
        // path.rQuadTo(300+200, 100+100, 300+400, 0);

        canvas.drawPath(path, paint);
    }

    public Path getPath() {
        return path;
    }

}

第二步:模拟Path类 封装一个自己的Path来 记录曲线运动坐标点。


     

package example.nzh.com.beisaier;


import android.util.ArrayMap;
import android.util.SparseArray;
import android.widget.ArrayAdapter;

import java.util.ArrayList;

public class MyPath {

    /**
     * 记录贝塞尔曲线控制点
     * key:点的 类型(控制点,起始点,终点)
     * value:点
     */
    ArrayMap<Integer, MyPoint> map;

    public MyPath() {
        this.map = new ArrayMap<>();
    }

    public void moveTo(float startX, float startY) {
        map.put(MyPoint.TYPE_START, new MyPoint(startX, startY, MyPoint.TYPE_START));
    }

    public void quadTo(float controlX, float controlY, float endX, float endY) {
        map.put(MyPoint.TYPE_QUAD_POINT, new MyPoint(controlX, controlY, MyPoint.TYPE_QUAD_POINT));
        map.put(MyPoint.TYPE_END, new MyPoint(endX, endY, MyPoint.TYPE_END));
    }


    /**
     * 返回 二阶贝塞尔曲线控制点
     *
     * @return
     */
    public MyPoint getQuadControlPoint() {
        return map.get(MyPoint.TYPE_QUAD_POINT);
    }

    /**
     * 返回起始点 ,终点 坐标 集合
     *
     * @return
     */
    public MyPoint[] getStartEndPoint() {
        MyPoint start = map.get(MyPoint.TYPE_START);
        MyPoint end = map.get(MyPoint.TYPE_END);
        MyPoint[] array = {start, end};
        return array;
    }


}
package example.nzh.com.beisaier;

public class MyPoint {
    public float x;
    public float y;

    public static final int TYPE_START = 1; //起始点
    public static final int TYPE_END = 2;  //终止点
    public static final int TYPE_QUAD_POINT = 3; //二阶贝塞尔曲线控制点
    public static final int TYPE_CUBIC_PIONT_1 = 4; //三阶贝塞尔曲线 控制点1
    public static final int TYPE_CUBIC_PIONT_2 = 5;//三阶贝塞尔曲线 控制点2

    int type;

    public MyPoint(float x, float y, int type) {
        this.x = x;
        this.y = y;
        this.type = type;
    }

    public MyPoint(float x, float y) {
        this.x = x;
        this.y = y;
    }
}

  第三步:实现贝塞尔运动估值器。并结合属性动画来控制view。

             

package example.nzh.com.beisaier;


import android.animation.TypeEvaluator;

public class BesselEvaluator implements TypeEvaluator<MyPoint> {

    MyPoint controlP1;

    /**
     * 二阶 贝塞尔曲线 控制点  构造
     *
     * @param controlP
     */
    public BesselEvaluator(MyPoint controlP) {
        this.controlP1 = controlP;
    }

    /**
     * @param t  动画执行的百分比
     * @param p0 起始坐标
     * @param p2 终止坐标
     * @return
     */
    @Override
    public MyPoint evaluate(float t, MyPoint p0, MyPoint p2) {

        //二阶贝塞尔曲线运动
        //公式:baidu

        float x = (1 - t) * (1 - t) * p0.x + 2 * t * (1 - t) * controlP1.x + t * t * p2.x;
        float y = (1 - t) * (1 - t) * p0.y + 2 * t * (1 - t) * controlP1.y + t * t * p2.y;
        MyPoint myPoint = new MyPoint(x, y);
        return myPoint;
    }
}

package example.nzh.com.beisaier;

import android.animation.ObjectAnimator;
import android.app.Activity;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Path;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;

import example.nzh.com.beisaier.canvas.CanvasActivity;
import example.nzh.com.beisaier.canvas.CanvasActivity2;
import example.nzh.com.beisaier.view.ViewGroupTestActivity;

public class MainActivity extends Activity implements View.OnClickListener {
    TextView textView;
    //利用属性动画 原理,定义一个属性 ,(贝塞尔曲线运动)
    private MyPoint besselMove;

    PathView pathView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        pathView = (PathView) findViewById(R.id.pathview);

        textView = (TextView) findViewById(R.id.textview);
        textView.setOnClickListener(this);

    }


    @Override
    public void onClick(View v) {
        MyPath myPath = new MyPath();
        // 保证这里的坐标和绘制的曲线坐标一致,这样就可以沿着曲线运动。
        myPath.moveTo(200, 200);
        myPath.quadTo(500, 700, 600, 200);


        ObjectAnimator animator = ObjectAnimator.ofObject(
                this,
                "besselMove",
                new BesselEvaluator(myPath.getQuadControlPoint()),
                myPath.getStartEndPoint());
        animator.setDuration(3 * 1000);
        animator.start();

    }

    /**
     * 提供属性的set方法
     *
     * @param besselMove
     */
    public void setBesselMove(MyPoint besselMove) {
        this.besselMove = besselMove;

        textView.setTranslationX(besselMove.x);
        textView.setTranslationY(besselMove.y);

    }
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值