用Android动画,如何让一个箭头按圆形旋转?
arrow like this:
arrow.png最终效果图:
效果图一、分析
1、两个关键值
箭头按圆形旋转,需要两个关键值,一个是圆形坐标,一个是对应圆形坐标位置的角度。
圆形坐标:用来实现箭头移动
坐标点的角度:用来改变箭头的方向
2、两个关键API
a、实现箭头移动和旋转可以使用:
Matrix 类 postTranslate和postRotate方法。
b、获取圆坐标,和对应的角度,可以使用:
PathMeasure类的getPosTan方法。
二、具体实现
1、先在屏幕重要画个圆:
//画布移到屏幕中心
canvas.translate((float) mWidth / 2, (float) mHeight / 2);
//画一个圆
mPath.addCircle(0, 0, 200, Path.Direction.CW);
canvas.drawPath(mPath, mPaint);
画之前需要先获取屏幕宽高(重写View的onSizeChanged):
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth = w;
mHeight = h;
}
2、获取圆形的某个位置坐标,和对应位置的角度。
PathMeasure pathMeasure = new PathMeasure(mPath,false);
//圆周长
float distance = pathMeasure.getLength();
//将distance段的实际坐标值和单位圆坐标值分别保持到pos、tan中
pathMeasure.getPosTan(distance,pos,tan);
float px = pos[0];//实际x坐标值
float py = pos[1];//实际y坐标值
//根据单位圆坐标值,计算出当前位置的角度值
float degrees = (float) (Math.atan2(tan[1],tan[0]) * 180/Math.PI);
3、绘制箭头
//获取图片宽高度
int width = mBitmap.getWidth();
int height = mBitmap.getHeight();
//设置箭头旋转角度
mMatrix.postRotate(degrees,(float) width/2,(float) height/2);
//设置箭头位置
mMatrix.postTranslate(px - (float) width/2,py- (float)height/2);
//绘制
canvas.drawBitmap(mBitmap,mMatrix,mPaint);
以上我们就可以将箭头显示在圆环上了,但是它还不能动起来,还只是静态的。
怎么让它转起来呢?
4、如何让箭头转起来呢?
我们需要不停的改变箭头的位置,和角度。
先定义一个成员变量:
private float mFloat = 0;
让mFloat 在0到1之间变化,然后再重新获取pos、和tan值:
mFloat += 0.01;
if(mFloat >= 1){
mFloat = 0;
}
pathMeasure.getPosTan(distance * mFloat,pos,tan);
然后再不停到重新绘制:
invalidate();
这样就可以让箭头转起来了。
最后附上完整代码:
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.util.Log;
import android.view.View;
import androidx.annotation.Nullable;
/**
* 图片圆型旋转动画
*/
public class CircleAnimatorView extends View {
public CircleAnimatorView(Context context) {
this(context, null);
}
public CircleAnimatorView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleAnimatorView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth = w;
mHeight = h;
}
private Paint mPaint = new Paint();
private Path mPath = new Path();
private int mWidth;
private int mHeight;
private Bitmap mBitmap;
//保持圆上xy的实际坐标
private float[] pos = new float[2];
//保持单位圆上xy的坐标
private float[] tan = new float[2];
private Matrix mMatrix = new Matrix();
private float mFloat = 0;
private void init() {
mPaint.setColor(Color.BLACK);
mPaint.setStrokeWidth(4);
mPaint.setStyle(Paint.Style.STROKE);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 4;//缩小4倍
mBitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.arrow,options);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//画布移到屏幕中心
canvas.translate((float) mWidth / 2, (float) mHeight / 2);
mPath.reset();
//添加一个圆
mPath.addCircle(0, 0, 200, Path.Direction.CW);
canvas.drawPath(mPath, mPaint);
PathMeasure pathMeasure = new PathMeasure(mPath,false);
//圆周长
float distance = pathMeasure.getLength();
mFloat += 0.01;
if(mFloat >= 1){
mFloat = 0;
}
pathMeasure.getPosTan(distance * mFloat,pos,tan);
float px = pos[0];
float py = pos[1];
float degrees = (float) (Math.atan2(tan[1],tan[0]) * 180/Math.PI);
Log.d("View-->","onDraw | degrees:"+degrees);
int width = mBitmap.getWidth();
int height = mBitmap.getHeight();
mMatrix.reset();
//必须选postRotate,再调用 postTranslate
mMatrix.postRotate(degrees,(float) width/2,(float) height/2);
mMatrix.postTranslate(px - (float) width/2,py- (float)height/2);
canvas.drawBitmap(mBitmap,mMatrix,mPaint);
invalidate();
}
}
网友评论