PathMeasure + 贝塞尔曲线实现过山车效果

时间:2023-02-10 00:08:14

先看效果图:
PathMeasure + 贝塞尔曲线实现过山车效果

思路:
1.首先绘制红色的贝塞尔曲线
2.然后用PathMeasure,测量曲线某一点A的长度、倾斜度、坐标
3.根据坐标倾斜度,绘制图片
4.根据PathMeasure获得,起始点O到A点的路径,绘制走过的路径

代码:

package com.test.paintdemo.pathrelate;

import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.Point;
import android.view.View;
import android.view.animation.LinearInterpolator;

import com.test.paintdemo.R;

import java.util.ArrayList;
import java.util.List;

public class WaveView extends View {

private Path mPath;
private Paint mPaint;

private Bitmap mBitMap;
private PathMeasure mPathMeasure;
private float[] pos;
private float[] tan;
private Matrix mMatrix;
private float faction;
private List<Point> list;
private Paint mPaintDst;
private Path dst;

public WaveView(Context context) {
super(context);
init();
startAnimation();
}

private void init() {
mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setAntiAlias(true);

mPaintDst = new Paint();
mPaintDst.set(mPaint);
mPaintDst.setStrokeWidth(3);
mPaintDst.setColor(Color.BLUE);

mPathMeasure = new PathMeasure();
mPath = new Path();
dst = new Path();
pos = new float[2];
tan = new float[2];
mMatrix = new Matrix();

BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
mBitMap = BitmapFactory.decodeResource(getResources(), R.drawable.timg,options);
list = new ArrayList<>();

}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//随机生成一堆坐标点
for (int i = 0; i < 20; i++) {
Point point = new Point();
point.x = (int) (Math.random() * w);
point.y = (int) (Math.random() * h);
list.add(point);
}
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//重置Path, Matrix
mPath.reset();
dst.reset();
mMatrix.reset();

//1.绘制贝塞尔曲线(轨道)
drawQuadPath(canvas);

//2.测量轨道path
mPathMeasure.setPath(mPath, false);
//获取轨道长度
float length = mPathMeasure.getLength();

//3.绘制图片(图片的坐标,倾斜角度)
// 方案一 :自己计算
// boolean posTan = mPathMeasure.getPosTan(length*faction,pos,tan);
// if(posTan){
// // 将tan值通过反正切函数得到对应的弧度,在转化成对应的角度度数
// float degrees = (float) (Math.atan2(tan[1],tan[0])*180f / Math.PI);
// mMatrix.postRotate(degrees, mBitMap.getWidth()/2, mBitMap.getHeight() / 2);
// mMatrix.postTranslate(pos[0]- mBitMap.getWidth() / 2,pos[1] - mBitMap.getHeight());
// canvas.drawBitmap(mBitMap,mMatrix,mPaint);
// }

// 方案二 :直接使用API
boolean matrix = mPathMeasure.getMatrix(length*faction, mMatrix, PathMeasure.TANGENT_MATRIX_FLAG | PathMeasure.POSITION_MATRIX_FLAG);
if(matrix) {
mMatrix.preTranslate(-mBitMap.getWidth() / 2, -mBitMap.getHeight());
canvas.drawBitmap(mBitMap, mMatrix, mPaint);
}

//4.获取图片移动过的轨迹
mPathMeasure.getSegment(0, length * faction, dst, true);
//绘制图片移动过的轨迹
canvas.drawPath(dst, mPaintDst);

}


private void drawQuadPath(Canvas canvas) {
for (int i = 0; i < list.size(); i+=2) {
if(i + 1 < list.size()) {
Point p1 = list.get(i);
Point p2 = list.get(i + 1);
mPath.quadTo(p1.x, p1.y, p2.x, p2.y);
}
}
mPath.lineTo(getWidth(), getHeight());
mPath.lineTo(0, getHeight());
mPath.close();
//绘制贝塞尔曲线
canvas.drawPath(mPath,mPaint);
}

public void startAnimation(){
ValueAnimator animator = ValueAnimator.ofFloat(0,1);
animator.setDuration(5000);
animator.setInterpolator(new LinearInterpolator());
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
faction = (float) animation.getAnimatedValue();
postInvalidate();
}
});
animator.start();
}

}