c.推导公式求解x和y。
辅助线我就不画了,我直接给出推导公式
转换成java代码如下
float tagX = (float) (Math.sin(Math.toRadians(60)) * mRadius / Math.cos(Math.toRadians(30 - swipeAgenl))
- Math.sin(Math.toRadians(60 - swipeAgenl)));
float tagY = (float) (Math.sin(Math.toRadians(60)) * mRadius / Math.cos(Math.toRadians(30 - swipeAgenl))
- Math.cos(Math.toRadians(60 - swipeAgenl))) - mRadius;
运行看下效果是不是符合预期
4.圆弧
点(0,-R)到(√3/2/R,R/2)点与圆相交处会有个圆弧。这里利用Path.addArc 或者canvas.drawArc 方法都可以绘制。所传参方式有两种,其实本质都是传入一个矩形然后在矩形框内绘制一个圆弧。
Path.java public void addArc(RectF oval, float startAngle, float sweepAngle) { addArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle); } Canvas.java public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter, @NonNull Paint paint) { drawArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, useCenter, paint); }
startAngle 为开始的角度,sweepAngle为圆弧滑过的角度。代码如下:
RectF oval = new RectF(-mRadius, -mRadius, mRadius, mRadius); mPaint.setStyle(Paint.Style.FILL); path.addArc(oval, -90, 60);
5.看看效果
画出了一个,那么6个就很好画,为了方面观察效果,我把每个都整成了不同颜色,方便大家看。
咦,不对劲呀,和我预想的不一样。我们可以再看看UI做的效果图。抛开图形旋转角度的因素,可以观察到,图形是随着时间的变化,红色边线一直拉长而形成的。最大长度是R,最小长度是0,或者你设置任意初始值,还有一点要注意,在红线延伸的过程中,夹角始终是60度。
6.重新计算
依旧是正弦函数,余弦函数,算出点在红线上的位置。
float L1 = (float) Math.sqrt(Math.pow(mRadius, 2.0) - Math.pow(Math.sin(Math.toRadians(60)) * a, 2.0));
float consL1 = L1 / mRadius; float sinL1 = (float) Math.sin(Math.toRadians(60)) * a / mRadius; float L = (float) (L1 + Math.sin(Math.toRadians(30)) * a);
float tagX = L * sinL; float tagY = L * consL - mRadius;
7.大功告成
/**
- @authoer create by markfrain
- @github https://github.com/furuiCQ
- 高怀见物理 和气得天真
- 时间: 4/28/21
- 描述: ShootView
*/ public class ShootView extends View { private static final int DEGREE_60 = 60;
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private final RectF mBounds = new RectF(); private int mRadius; private int mCenterX; private int mCenterY;
private ValueAnimator mPlayAnimator; private float swipeAgenl = mRadius;//延伸的距离
private float mShootLineTotalRotateAngle;//旋转角度 private ValueAnimator mPreShootLineTotalRotateAnimator;
private float padding = 20; private ValueAnimator paddingAnimator;
private float fix = 4; private ValueAnimator fixAnimator;
private static final float SHOOT_LINE_ROTATE_END_RADIANS = (float) (Math.PI / 6.0);//旋转结束弧度 private static final float SHOOT_LINE_ROTATE_START_RADIANS = (float) (Math.PI / 2.0);//旋转开始弧度 private static final float SHOOT_LINE_ROTATE_START_DEGREE = (float) Math.toDegrees(SHOOT_LINE_ROTATE_END_RADIANS);//旋转开始角度 private static final int PRE_SHOOT_LINE_TOTAL_ROTATE_DURATION = 1000;
public static final Property<ShootView, Float> SHOOT_LINE_TOTAL_ROTATE_DEGREE = new Property<ShootView, Float>(Float.class, null) { @Override public Float get(ShootView object) { return object.mShootLineTotalRotateAngle; }
@Override public void set(ShootView object, Float value) { object.mShootLineTotalRotateAngle = value; object.invalidate(); } };
public ShootView(Context context) { this(context, null); }
public ShootView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); }
public ShootView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(5); mPaint.setColor(Color.parseColor("#ffc6c6c6"));
paddingAnimator = ValueAnimator.ofFloat(20, 0); paddingAnimator.setInterpolator(new LinearInterpolator()); paddingAnimator.setDuration(PRE_SHOOT_LINE_TOTAL_ROTATE_DURATION); paddingAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { padding = (float) animation.getAnimatedValue(); invalidate(); } }); fixAnimator = ValueAnimator.ofFloat(4, 0); fixAnimator.setInterpolator(new LinearInterpolator()); fixAnimator.setDuration(1200); fixAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Ov
《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享
erride public void onAnimationUpdate(ValueAnimator animation) { fix = (float) animation.getAnimatedValue(); invalidate(); } });
mPreShootLineTotalRotateAnimator = ValueAnimator.ofFloat(-(SHOOT_LINE_ROTATE_START_DEGREE / 2.0f) - 240.0f, -(SHOOT_LINE_ROTATE_START_DEGREE / 2.0f) - 120.0f); mPreShootLineTotalRotateAnimator.setInterpolator(new LinearInterpolator()); mPreShootLineTotalRotateAnimator.setDuration(PRE_SHOOT_LINE_TOTAL_ROTATE_DURATION); mPreShootLineTotalRotateAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mShootLineTotalRotateAngle = (float) animation.getAnimatedValue(); invalidate(); } }); }
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas);
// drawTest(canvas); drawArc(canvas); drawCircle(canvas);
}
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mBounds.set(0 + getPaddingLeft(), 0 + getPaddingTop(), w - getPaddingRight(), h - getPaddingBottom());
mRadius = (int) (Math.min(mBounds.width(), mBounds.height()) / 2); mCenterX = (int) mBounds.centerX(); mCenterY = (int) mBounds.centerY(); swipeAgenl = mRadius * 2 / 3f; }
float mStartX; float mStartY;
int colors[] = {Color.RED, Color.GREEN, Color.YELLOW, Color.MAGENTA, Color.CYAN, Color.GRAY};
private void drawTest(Canvas canvas) { drawCircle(canvas); canvas.save(); canvas.translate(mCenterX, mCenterY);
int i = 0; canvas.save(); canvas.rotate(-DEGREE_60 * i); Path path = new Path();
float stopX = (float) Math.sqrt(3) * mRadius / 2f; float stopY = -mRadius / 2f;
canvas.drawLine(0, -mRadius, stopX, stopY, mPaint); mPaint.setColor(Color.RED); canvas.drawPoint(stopX, stopY, mPaint); mPaint.setColor(Color.RED);
//canvas.drawLine(0, 0, stopX, stopY, mPaint);
RectF oval = new RectF(-mRadius, -mRadius, mRadius, mRadius);
RectF rectF = new RectF(-mRadius, -2 * mRadius, mRadius, 0);
mPaint.setStyle(Paint.Style.FILL); path.addArc(oval, -90, 60);
//计算直接点的 float tagX = (float) (Math.sin(Math.toRadians(60)) * mRadius / Math.cos(Math.toRadians(30 - swipeAgenl)) * Math.sin(Math.toRadians(60 - swipeAgenl))); float tagY = (float) (Math.sin(Math.toRadians(60)) * mRadius / Math.cos(Math.toRadians(30 - swipeAgenl)) * Math.cos(Math.toRadians(60 - swipeAgenl))) - mRadius;
// float tagX = Math.sqrt(Math.pow(mRadius,2.0) - Math.pow(Math.sin(Math.toRadians(60) * swipeAgenl), 2.0));
// float L = (float) Math.sqrt(Math.pow(mRadius, 2.0) - Math.pow(Math.sin(Math.toRadians(60)) * swipeAgenl, 2.0)); // float consL = L / mRadius; // float sinL = (float) Math.sin(Math.toRadians(60)) * swipeAgenl / mRadius; // float LL = (float) (L + Math.sin(Math.toRadians(30)) * swipeAgenl); // // float tagX = LL * sinL; // float tagY = LL * consL - mRadius;
canvas.drawPoint(tagX, tagY, mPaint);
// path.moveTo(stopX, stopY); // path.lineTo(tagX, tagY); // path.lineTo(0, -mRadius); canvas.drawPath(path, mPaint); // }
}
private void drawArc(Canvas canvas) {
canvas.save(); canvas.translate(mCenterX, mCenterY); canvas.rotate(mShootLineTotalRotateAngle); for (int i = 0; i < 6; i++) { canvas.save(); canvas.rotate(-DEGREE_60 * i); Path path = new Path(); mPaint.setColor(colors[i]); RectF oval = new RectF(-mRadius, -mRadius, mRadius, mRadius); mPaint.setStyle(Paint.Style.FILL);
// mRadius- padding double asin = Math.toDegrees(Math.asin((mRadius - padding) / mRadius / 2)) * 2; path.addArc(oval, -90, (float) asin);
; mPaint.setColor(colors[i]); RectF oval = new RectF(-mRadius, -mRadius, mRadius, mRadius); mPaint.setStyle(Paint.Style.FILL);
// mRadius- padding double asin = Math.toDegrees(Math.asin((mRadius - padding) / mRadius / 2)) * 2; path.addArc(oval, -90, (float) asin);
|