1. 程式人生 > >android高階動畫——貝塞爾曲線

android高階動畫——貝塞爾曲線

Android高階動畫所有程式碼

簡介:貝塞爾曲線是計算機圖形學中相當重要的引數曲線。可以用數學公式來描述一段曲線。

用途:1、貝塞爾曲線可以幫助我們在二維平面內用平滑的曲線畫出各種圖形。

2、同時也可以給動畫提供一個平滑的曲線運動路徑。

android中我們通過Path可以畫出二階跟三階貝塞爾曲線。複雜的圖形我們可以組合幾個二階和三階的貝塞爾曲線就可以實現。

這次整理一下沿著二階貝塞爾曲線運動的例子。下面是一個沿著二階貝塞爾曲線運動的小球的程式碼和講解。

示例程式碼:

1、總共有4個程式碼檔案activity、view、Evalutor和xml檔案。

2、先分析下最重要的view檔案:

public class TestMove extends View implements View.OnClickListener
{
    private float mCircleX,mCircleY;    //小球的圓心

    private Path mMovePath;         //這是用來畫貝塞爾曲線的
    private Paint mPaintBezier,mPaintCircle;    //設定畫貝塞爾曲線和園的畫筆

    private float mStartPointX,mStartPointY;    //二階貝塞爾曲線的起始點
    private float mEndPointX,mEndPointY;        //二階貝塞爾曲線的終點
    private float mFlagPointX,mFlagPointY;      //二階貝塞爾曲線的支撐點


    public TestMove(Context context) {
        super(context);
    }

    public TestMove(Context context, AttributeSet attrs) {
        super(context, attrs);

        //初始化畫筆
        mPaintBezier=new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaintBezier.setStrokeWidth(8);
        mPaintBezier.setStyle(Paint.Style.STROKE);
        mPaintBezier.setColor(Color.BLUE);

        mPaintCircle=new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaintCircle.setStrokeWidth(8);
        mPaintCircle.setStyle(Paint.Style.FILL_AND_STROKE);
        mPaintCircle.setColor(Color.BLUE);

        setOnClickListener(this);
    }

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

        /**
         * 系統每一次需要計算大小時都會執行這個方法,比如view改變的時候。所以我們在這裡
         * 獲得起始點、終點和支撐點
         */
        mStartPointX = w / 4;
        mStartPointY = h / 2 - 200;

        mEndPointX = w * 3 / 4;
        mEndPointY = h / 2 - 200;

        mFlagPointX = w / 2;
        mFlagPointY = h / 2 - 400;

        mCircleX=mStartPointX;
        mCircleY=mStartPointY;

        mMovePath=new Path();

    }

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

        //畫圓
        canvas.drawCircle(mCircleX,mCircleY,30,mPaintCircle);

        //給Path設定貝塞爾曲線,然後canvas畫
        mMovePath.reset();
        mMovePath.moveTo(mStartPointX,mStartPointY);
        /**
         * quadTo()繪製二階貝塞爾曲線
         * cubicTo()繪製三階貝塞爾曲線
         */
        mMovePath.quadTo(mFlagPointX,mFlagPointY,mEndPointX,mEndPointY);
        canvas.drawPath(mMovePath,mPaintBezier);

    }

    @Override
    public void onClick(View v) {
        PointF flagPoint1=new PointF(mFlagPointX,mFlagPointY);

        PointF startPoint=new PointF(mStartPointX,mStartPointY);
        PointF endPoint=new PointF(mEndPointX,mEndPointY);

        /**
         * 在startPoint和endPoint之間運動時返回一個ValueAnimator的值
         * MoveEvalutor在它的檔案裡詳細解釋
         */
        ValueAnimator mValueAnimator=ValueAnimator.ofObject(new MoveEvalutor(flagPoint1),
                startPoint,endPoint);
        mValueAnimator.setDuration(4000);
        mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                /**
                 * 把小球的圓心設定到運動點
                 */
                PointF point=(PointF) animation.getAnimatedValue();
                mCircleX=point.x;
                mCircleY=point.y;
                invalidate();
            }
        });
        mValueAnimator.start();
    }
}

3MoveEvalutor.java的程式碼:

/**
 * Created by zhaofeng on 2017/2/13.
 *
 * Evalutor允許開發者在任意型別上建立動畫,以此來執行動畫系統不能直接識別的動畫型別。
 */

public class MoveEvalutor implements TypeEvaluator<PointF>{

    private PointF mFlagPoint1;

    public MoveEvalutor(PointF flagPoint) {
        mFlagPoint1=flagPoint;
    }
    @Override
    public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
        return CalculateBezierPointForQuadratic(fraction,startValue,mFlagPoint1,endValue);
    }
    /**
     * B(t) = (1 - t)^2 * P0 + 2t * (1 - t) * P1 + t^2 * P2, t ∈ [0,1]
     *計算貝塞爾曲線的運動點,這個程式碼在網上可以找到,二階的三階的。
     * @param t  曲線長度比例
     * @param p0 起始點
     * @param p1 控制點
     * @param p2 終止點
     * @return t對應的點
     */
    public static PointF CalculateBezierPointForQuadratic(float t, PointF p0, PointF p1, PointF p2) {
        PointF point = new PointF();
        float temp = 1 - t;
        point.x = temp * temp * p0.x + 2 * t * temp * p1.x + t * t * p2.x;
        point.y = temp * temp * p0.y + 2 * t * temp * p1.y + t * t * p2.y;
        return point;
    }
}

4、在activity_move_on_bezier.xml,在xml檔案中引入view檔案。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_move_on_bezier"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.zfeng.bazier.MoveOnBezierActivity">
    <com.zfeng.bazier.view.MoveOnBezierView
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>
5、在activity中執行:
public class MoveOnBezierActivity extends AppCompatActivity {

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

以上就是全部的程式碼,點選view,小球就會沿著二階貝塞爾曲線運動。

參考資料: