旋转的箭头
这里是一个箭头,我们要做的效果就是这个箭头绕着一个圆自动旋转,我们看下代码
方案一:
package com.example.testpathmeasure;
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.util.AttributeSet;
import android.view.View;
import androidx.annotation.Nullable;
/**
* @author writing
* @time 2019/12/25 13:53
* @note
*/
public class PathMeasureView extends View {
private float currentValue = 0;//用于记录当前的位置,取值范围为[0,1],映射Path的整个长度
private float[] pos; //当前点的实际位置
private float[] tan; // 当前点的tangent值,用于计算图片所需旋转的角度
private Bitmap mBitmap;//箭头图片
private Matrix mMatrix; //矩形,用于对图片进行一些操作
private Paint mDefaultPaint;
private int mViewWidth;
private int mViewHeight;
private Paint mPaint;
public PathMeasureView(Context context) {
super(context);
inint(context);
}
public PathMeasureView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
inint(context);
}
public PathMeasureView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
inint(context);
}
public PathMeasureView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
inint(context);
}
private void inint(Context context) {
pos = new float[2];
tan = new float[2];
BitmapFactory.Options options = new BitmapFactory.Options();
// options.inSampleSize = 8;//缩放图片
mBitmap = BitmapFactory.decodeResource(context.getResources(),R.mipmap.arrow,options);
mMatrix = new Matrix();
mDefaultPaint = new Paint();
mDefaultPaint.setColor(Color.RED);
mDefaultPaint.setStrokeWidth(5);
mDefaultPaint.setStyle(Paint.Style.STROKE);
mPaint = new Paint();
mPaint.setColor(Color.DKGRAY);
mPaint.setStrokeWidth(2);
mPaint.setStyle(Paint.Style.STROKE);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//指定View的宽高
mViewHeight = h;
mViewWidth = w;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
currentValue+=0.005;
if(currentValue>=1){
currentValue = 0;
}
//平移坐标系,使坐标系位于中心点
canvas.translate(mViewWidth/2,mViewHeight/2);
//画坐标轴
canvas.drawLine(0,-canvas.getHeight(),0,canvas.getHeight(),mPaint);
canvas.drawLine(-canvas.getWidth(),0,canvas.getWidth(),0,mPaint);
Path path = new Path();
//顺时针绘制圆
path.addCircle(0,0,300, Path.Direction.CW);
canvas.drawPath(path,mDefaultPaint);
PathMeasure pathMeasure = new PathMeasure(path,false);
//获取指定长度位置的矩阵
pathMeasure.getMatrix(pathMeasure.getLength()*currentValue,mMatrix,PathMeasure.TANGENT_MATRIX_FLAG|PathMeasure.POSITION_MATRIX_FLAG);
//设置矩阵偏移,不然纸飞机的尖不会对准圆圈。设置矩阵偏移的时候要把矩阵的坐标系与cavans的坐标系保持一致。
//保证矩阵的坐标系平行于屏幕的长和宽。当矩阵旋转的时候,矩阵的坐标系也会旋转,这一点要牢记。
mMatrix.preTranslate(-mBitmap.getWidth()/2,-mBitmap.getHeight()/2);
//绘制飞机
canvas.drawBitmap(mBitmap,mMatrix,mDefaultPaint);
invalidate();
}
}
运行的效果,飞机在不停的旋转
方案二,与方案一效果一模一样
package com.example.testpathmeasure;
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.util.AttributeSet;
import android.view.View;
import androidx.annotation.Nullable;
/**
* @author writing
* @time 2019/12/25 13:53
* @note
*/
public class PathMeasureView1 extends View {
private float currentValue = 0;//用于记录当前的位置,取值范围为[0,1],映射Path的整个长度
private float[] pos; //当前点的实际位置
private float[] tan; // 当前点的tangent值,用于计算图片所需旋转的角度
private Bitmap mBitmap;//箭头图片
private Matrix mMatrix; //矩形,用于对图片进行一些操作
private Paint mDefaultPaint;
private int mViewWidth;
private int mViewHeight;
private Paint mPaint;
public PathMeasureView1(Context context) {
super(context);
inint(context);
}
public PathMeasureView1(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
inint(context);
}
public PathMeasureView1(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
inint(context);
}
public PathMeasureView1(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
inint(context);
}
private void inint(Context context) {
pos = new float[2];
tan = new float[2];
BitmapFactory.Options options = new BitmapFactory.Options();
// options.inSampleSize = 8;//缩放图片
mBitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.arrow, options);
mMatrix = new Matrix();
mDefaultPaint = new Paint();
mDefaultPaint.setColor(Color.RED);
mDefaultPaint.setStrokeWidth(5);
mDefaultPaint.setStyle(Paint.Style.STROKE);
mPaint = new Paint();
mPaint.setColor(Color.DKGRAY);
mPaint.setStrokeWidth(2);
mPaint.setStyle(Paint.Style.STROKE);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//指定View的宽高
mViewHeight = h;
mViewWidth = w;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
currentValue += 0.005;
if (currentValue >= 1) {
currentValue = 0;
}
canvas.translate(mViewWidth/2,mViewHeight/2);
canvas.drawLine(canvas.getWidth(),0,-canvas.getWidth(),0,mPaint);
canvas.drawLine(0,canvas.getWidth(),0,-canvas.getWidth(),mPaint);
Path path = new Path();
path.addCircle(0, 0, 300, Path.Direction.CW);
canvas.drawPath(path,mPaint);
PathMeasure pathMeasure = new PathMeasure(path,false);
pathMeasure.getPosTan(pathMeasure.getLength()*currentValue,pos,tan);
mMatrix.reset();
//Math.atan2(x,y)*180/Math.PI表示x,y这一点和原点连线的正切值。如Math.atan2(9,9)*180/Math.PI的值就是45,即9/9的正切值的角的度数
float degree = (float) (Math.atan2(tan[1],tan[0])*180/Math.PI);
//旋转图片
mMatrix.postRotate(degree,mBitmap.getWidth()/2,mBitmap.getHeight()/2);
//将图片中心调整到与当前点重合
mMatrix.postTranslate(pos[0]-mBitmap.getWidth()/2,pos[1]-mBitmap.getWidth()/2);
canvas.drawPath(path,mPaint);
canvas.drawBitmap(mBitmap,mMatrix,mDefaultPaint);
invalidate();
}
}
转动的loading
package com.example.testpathmeasure;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import androidx.annotation.Nullable;
/**
* @author writing
* @time 2019/12/26 12:55
* @note
*/
public class LoadingView extends View {
private Path mPath;
private Paint mPaint;
private PathMeasure mPathMeasure;
private float mAnimatorValue;
private Path mDst;
private float mLength;
public LoadingView(Context context) {
this(context,null);
}
public LoadingView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,-1);
}
public LoadingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr,-1);
}
public LoadingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
innit();
}
private void innit() {
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5);
mPath = new Path();
mPath.addCircle(400,400,100, Path.Direction.CCW);
mPathMeasure = new PathMeasure(mPath,true);
mLength = mPathMeasure.getLength();
mDst = new Path();
startAnima();
}
private void startAnima() {
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0,1);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mAnimatorValue = (float) valueAnimator.getAnimatedValue();
invalidate();
}
});
valueAnimator.setDuration(2000);
valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
valueAnimator.start();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mDst.reset();
//避免硬件加速带来的问题
mDst.lineTo(0,0);
float end = mLength*mAnimatorValue;
float start = (float) (end-((0.5-Math.abs(mAnimatorValue-0.5))*mLength));
Log.i("zhang_xin","start:"+start);
mPathMeasure.getSegment(start,end,mDst,true);
canvas.drawPath(mDst,mPaint);
}
}
小船随波浪线动
package com.dn_alan.myapplication;
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.util.Log;
import android.view.View;
import android.view.animation.LinearInterpolator;
/**
* 小船滑动
*/
public class WaveView extends View {
private static final int INT_WAVE_LENGTH = 1000;
private static final String TAG = "WaveView";
private Path mPath;
private Paint mPaint;
private int mDeltaX;
private Bitmap mBitMap;
private PathMeasure mPathMeasure;
private float[] pos;
private float[] tan;
private Matrix mMatrix;
private float faction;
public WaveView(Context context) {
super(context);
init();
}
private void init() {
mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPath = 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);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPath.reset();
int orginY = 800;
int halfWaveLength = INT_WAVE_LENGTH / 2;
mPath.moveTo(-INT_WAVE_LENGTH + mDeltaX, orginY);
for(int i = -INT_WAVE_LENGTH ; i < getWidth() + INT_WAVE_LENGTH;
i += INT_WAVE_LENGTH){
mPath.rQuadTo(halfWaveLength/2,120,halfWaveLength,0);
mPath.rQuadTo(halfWaveLength/2,-120,halfWaveLength,0);
}
mPath.lineTo(getWidth(),getHeight());
mPath.lineTo(0,getHeight());
mPath.close();
canvas.drawPath(mPath,mPaint);
mPathMeasure = new PathMeasure(mPath,false);
float length = mPathMeasure.getLength();
mMatrix.reset();
boolean posTan = mPathMeasure.getPosTan(length*faction,pos,tan);
canvas.drawCircle(tan[0],tan[1],20,mPaint);
canvas.drawLine(tan[0],tan[1],pos[0],pos[1],mPaint);
Log.i(TAG,"----------------------pos[0] = " + pos[0] + "pos[1] = " +pos[1]);
Log.i(TAG,"----------------------tan[0] = " + tan[0] + "tan[1] = " +tan[1]);
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
//直接帮你算了角度并且帮你进行了旋转
mPathMeasure.getMatrix(length*faction, mMatrix, PathMeasure.TANGENT_MATRIX_FLAG | PathMeasure.POSITION_MATRIX_FLAG);
mMatrix.preTranslate(- mBitMap.getWidth() / 2, - mBitMap.getHeight());
canvas.drawBitmap(mBitMap,mMatrix,mPaint);
}
//
}
public void startAnimation(){
//波浪动
// ValueAnimator anim = ValueAnimator.ofInt(0,INT_WAVE_LENGTH);
// anim.setDuration(1000);
// anim.setInterpolator(new LinearInterpolator());
// anim.setRepeatCount(ValueAnimator.INFINITE);
// anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
// @Override
// public void onAnimationUpdate(ValueAnimator animation) {
// mDeltaX = (int) animation.getAnimatedValue();
// postInvalidate();
// }
// });
// anim.start();
ValueAnimator animator = ValueAnimator.ofFloat(0,1);
animator.setDuration(10000);
animator.setInterpolator(new LinearInterpolator());
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
faction = (float) animation.getAnimatedValue();
Log.i(TAG,"----------------------faction = " + faction);
postInvalidate();
}
});
animator.start();
}
}
package com.dn_alan.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends AppCompatActivity {
private WaveView mWaveView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mWaveView = new WaveView(this);
setContentView(mWaveView);
mWaveView.startAnimation();
}
}