圆弧周围的箭头是我想要绘制的
以下是动画弧的代码。
我添加的代码将动画弧绘制到另一个弧上的触摸点。弧形填充所提供的渐变颜色到弧上的触摸点。弧的填充是动画。动画的代码有效。我想在电弧后面的弧线周围绘制一个箭头,直到它被填充的点。最终结果必须是弧后的箭头。
请帮助我。
//Rectangle for the arc
private RectF mArcRect = new RectF();
//Paints required for drawing
private Paint mArcPaint;
private Paint mArcProgressPaint;
private Paint mTickPaint;
private Paint mTickProgressPaint;
private Paint mTickTextPaint;
private Paint mTickTextColoredPaint;
private Paint linePaint;
//Arc related dimens
private int mArcRadius = 0;
private int mArcWidth = 2;
private int mArcProgressWidth = 18;
private boolean mRoundedEdges = true;
//Thumb Drawable
private Drawable mThumb;
//Thumb position related coordinates
private int mTranslateX;
private int mTranslateY;
private int mThumbXPos;
private int mThumbYPos;
private int mAngleTextSize = 12;
private int LOWER_LIMIT = -16;
private int mTickOffset = 12;
private int mTickLength = 10;
private int mTickWidth = 2;
private int mTickProgressWidth = 2;
private int mAngle = LOWER_LIMIT;
private boolean mTouchInside = true;
private boolean mEnabled = true;
private TicksBetweenLabel mTicksBetweenLabel = TicksBetweenLabel.TWO;
private int mTickIntervals = 15;
private double mTouchAngle = 0;
private float mTouchIgnoreRadius;
private int sweepAngle = 0;
private int oldAngle = 0;
private int bottomLeft;
private int top;
private long startClickTime = 0;
//Event listener
private OnProtractorViewChangeListener mOnProtractorViewChangeListener = null;
//Interface for event listener
public interface OnProtractorViewChangeListener {
void onProgressChanged(ProtractorView protractorView, double progress, boolean fromUser);
void onStartTrackingTouch(ProtractorView protractorView);
void onStopTrackingTouch(ProtractorView protractorView);
}
public enum TicksBetweenLabel {
ZERO,
ONE,
TWO,
THREE
}
public ProtractorView(Context context) {
super(context);
init(context, null, 0);
}
public ProtractorView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, R.attr.protractorViewStyle);
}
public ProtractorView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr);
}
private void init(Context context, AttributeSet attrs, int defStyle) {
final Resources res = getResources();
int textColor = res.getColor(R.color.progress_gray);
int textProgressColor = res.getColor(R.color.default_blue_light);
int tickColor = res.getColor(R.color.progress_gray);
int tickProgressColor = res.getColor(R.color.default_blue_light);
int thumbHalfHeight;
int thumbHalfWidth;
mThumb = res.getDrawable(R.drawable.thumb_selector);
mArcWidth = (int)(mArcWidth * DENSITY);
mArcProgressWidth = (int)(mArcProgressWidth * DENSITY);
mAngleTextSize = (int)(mAngleTextSize * DENSITY);
mTickOffset = (int)(mTickOffset * DENSITY);
mTickLength = (int)(mTickLength * DENSITY);
mTickWidth = (int)(mTickWidth * DENSITY);
mTickProgressWidth = (int)(mTickProgressWidth * DENSITY);
if (attrs != null) {
final TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ProtractorView, defStyle, 0);
Drawable thumb = array.getDrawable(R.styleable.ProtractorView_thumb);
if (thumb != null) {
mThumb = thumb;
}
thumbHalfHeight = mThumb.getIntrinsicHeight() / 2;
thumbHalfWidth = mThumb.getIntrinsicWidth() / 2;
mThumb.setBounds(-thumbHalfWidth, -thumbHalfHeight, thumbHalfWidth, thumbHalfHeight);
//Dimensions
mAngleTextSize = (int) array.getDimension(R.styleable.ProtractorView_angleTextSize, mAngleTextSize);
mArcProgressWidth = (int) array.getDimension(R.styleable.ProtractorView_progressWidth, mArcProgressWidth);
mTickOffset = (int) array.getDimension(R.styleable.ProtractorView_tickOffset, mTickOffset);
mTickLength = (int) array.getDimension(R.styleable.ProtractorView_tickLength, mTickLength);
mArcWidth = (int) array.getDimension(R.styleable.ProtractorView_arcWidth, mArcWidth);
//Integers
mAngle = array.getInteger(R.styleable.ProtractorView_angle, mAngle);
mTickIntervals = array.getInt(R.styleable.ProtractorView_tickIntervals, mTickIntervals);
//Colors
textColor = array.getColor(R.styleable.ProtractorView_textColor, textColor);
textProgressColor = array.getColor(R.styleable.ProtractorView_textProgressColor, textProgressColor);
tickColor = array.getColor(R.styleable.ProtractorView_tickColor, tickColor);
tickProgressColor = array.getColor(R.styleable.ProtractorView_tickProgressColor, tickProgressColor);
//Boolean
mRoundedEdges = array.getBoolean(R.styleable.ProtractorView_roundEdges, mRoundedEdges);
mEnabled = array.getBoolean(R.styleable.ProtractorView_enabled, mEnabled);
mTouchInside = array.getBoolean(R.styleable.ProtractorView_touchInside, mTouchInside);
int ordinal = array.getInt(R.styleable.ProtractorView_ticksBetweenLabel, mTicksBetweenLabel.ordinal());
mTicksBetweenLabel = TicksBetweenLabel.values()[ordinal];
}
/**
* Creating and configuring the paints as required.
*/
mAngle = (mAngle > MAX) ? MAX : ((mAngle < 0) ? LOWER_LIMIT : mAngle);
int[] colors = buildColorArray("60");
mArcPaint = new Paint();
mArcPaint.setShader(new LinearGradient(0, 0, 550, 0, colors, null, Shader.TileMode.MIRROR));
mArcPaint.setAntiAlias(true);
mArcPaint.setStyle(Paint.Style.STROKE);
mArcPaint.setStrokeWidth(mArcWidth);
int[] foregroundColors = buildColorArray("");
mArcProgressPaint = new Paint();
mArcProgressPaint.setShader(new LinearGradient(0, 0, 550, 0, foregroundColors, null, Shader.TileMode.MIRROR));
mArcProgressPaint.setAntiAlias(true);
mArcProgressPaint.setStyle(Paint.Style.STROKE);
mArcProgressPaint.setStrokeWidth(mArcProgressWidth);
if (mRoundedEdges) {
mArcPaint.setStrokeCap(Paint.Cap.ROUND);
mArcProgressPaint.setStrokeCap(Paint.Cap.ROUND);
}
mTickPaint = new Paint();
mTickPaint.setColor(tickColor);
mTickPaint.setAntiAlias(true);
mTickPaint.setStyle(Paint.Style.STROKE);
mTickPaint.setStrokeWidth(mTickWidth);
mTickProgressPaint = new Paint();
mTickProgressPaint.setColor(tickProgressColor);
mTickProgressPaint.setAntiAlias(true);
mTickProgressPaint.setStyle(Paint.Style.STROKE);
mTickProgressPaint.setStrokeWidth(mTickProgressWidth);
mTickTextPaint = new Paint();
mTickTextPaint.setColor(textColor);
mTickTextPaint.setAntiAlias(true);
mTickTextPaint.setStyle(Paint.Style.FILL);
mTickTextPaint.setTextSize(mAngleTextSize);
mTickTextPaint.setTextAlign(Paint.Align.CENTER);
mTickTextColoredPaint = new Paint();
mTickTextColoredPaint.setColor(textProgressColor);
mTickTextColoredPaint.setAntiAlias(true);
mTickTextColoredPaint.setStyle(Paint.Style.FILL);
mTickTextColoredPaint.setTextSize(mAngleTextSize);
mTickTextColoredPaint.setTextAlign(Paint.Align.CENTER);
linePaint = new Paint();
linePaint.setColor(Color.BLACK);
linePaint.setAntiAlias(true);
linePaint.setStyle(Paint.Style.STROKE);
}
private int[] buildColorArray(String alpha) {
//#ffc0c0
//#fd708a
//#54fcff
// String [] colors = {"#" + alpha + "60f0f6", "#" + alpha + "fd708a", "#" + alpha + "fd708a", "#" + alpha + "60f0f6", "#" + alpha + "d683a0", "#" + alpha + "60f0f6"};
String[] colors = {
"#" + alpha + "60f0f6",
"#" + alpha + "69dee9",
"#" + alpha + "99bbcd",
"#" + alpha + "fd708a",
"#" + alpha + "f8849b"
};
int[] colorValues = new int[colors.length]; //#59dae1
int j = 0;
for (int i = 0; i < colors.length; i++) {
colorValues[j++] = Color.parseColor(colors[i]); //60f0f6, 54fcff, fd708a
if (Util.IS_DEBUG_LOGGABLE) {
Log.d(TAG, "Color value: " + colors[i]);
}
}
return colorValues;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = getDefaultSize(getSuggestedMinimumHeight(),
heightMeasureSpec);
int width = getDefaultSize(getSuggestedMinimumWidth(),
widthMeasureSpec);
int min = Math.min(width, height);
//width = min;
height = min / 2;
int arcDiameter = 0;
int tickEndToArc = (mTickOffset + mTickLength);
int radiusConstant = 30;
arcDiameter = min - 2 * tickEndToArc + radiusConstant;
arcDiameter = (int)(arcDiameter - 2 * 20 * DENSITY);
mArcRadius = arcDiameter / 2;
top = height - (mArcRadius);
bottomLeft = width / 2 - mArcRadius;
mArcRect.set(bottomLeft, top, bottomLeft + arcDiameter, top + arcDiameter);
mTranslateX = (int) mArcRect.centerX();
mTranslateY = (int) mArcRect.centerY();
int thumbAngle = mAngle;
mThumbXPos = (int)(mArcRadius * Math.cos(Math.toRadians(thumbAngle)));
mThumbYPos = (int)(mArcRadius * Math.sin(Math.toRadians(thumbAngle)));
if (Util.IS_DEBUG_LOGGABLE) {
Log.d(TAG, "co ordinate = x = " + mThumbXPos + " y = " + mThumbYPos + " mAngle = " + mAngle);
}
setTouchInside(mTouchInside);
setMeasuredDimension(width, height + tickEndToArc + 33);
}
@SuppressLint("DrawAllocation")
@Override
protected void onDraw(Canvas canvas) {
if (mAngle > 0) {
mAngle = mAngle - 360;
}
if (mAngle <= 0 && mAngle > LOWER_LIMIT) {
mAngle = LOWER_LIMIT;
}
if (mTouchAngle > START_ANGLE && mTouchAngle < THRESHOLD_VALUE) {
mAngle = LOWER_LIMIT;
}
sweepAngle = mAngle;
if (Util.IS_DEBUG_LOGGABLE) {
Log.d(TAG, "The Sweep Angle is : " + sweepAngle);
}
if (sweepAngle < -280) {
mAngle = LOWER_LIMIT;
}
if (Util.IS_DEBUG_LOGGABLE) {
Log.d(TAG, "Max angle " + mAngle);
}
if ((double)(mAngle / 13) > 19) {
if (Util.IS_DEBUG_LOGGABLE) {
Log.d(TAG, "Inside If condition to set Complete angle");
}
mAngle = COMPLETE_ANGLE;
}
canvas.save();
canvas.scale(1, -1, mArcRect.centerX(), mArcRect.centerY());
canvas.drawArc(mArcRect, 0, MAX, false, mArcPaint);
canvas.drawArc(mArcRect, (int) START_ANGLE, mAngle, false, mArcProgressPaint);
canvas.restore();
double slope, startTickX, startTickY, endTickX, endTickY, midTickX, midTickY, thetaInRadians;
double radiusOffset = mArcRadius + mTickOffset;
}
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
if (mThumb != null && mThumb.isStateful()) {
int[] state = getDrawableState();
mThumb.setState(state);
}
invalidate();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mEnabled) {
this.getParent().requestDisallowInterceptTouchEvent(true);
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
if (ignoreTouch(event.getX(), event.getY())) {
return false;
}
if (ignoreAngleTouch(event.getX(), event.getY())) {
return false;
}
onStartTrackingTouch();
oldAngle = getAngle();
if (Util.IS_DEBUG_LOGGABLE) {
Log.d(TAG, "onTouchEvent: ACTION_DOWN old angle" + getAngle());
}
startClickTime = Calendar.getInstance().getTimeInMillis();
updateOnTouch(event);
break;
case MotionEvent.ACTION_MOVE:
if (Util.IS_DEBUG_LOGGABLE) {
Log.d(TAG, "ACTION_MOVE TRIGGERED");
}
if (ignoreAngleTouch(event.getX(), event.getY())) {
return false;
}
updateOnTouchForMove(event);
break;
case MotionEvent.ACTION_UP:
onStopTrackingTouch();
if (Util.IS_DEBUG_LOGGABLE) {
Log.d(TAG, "onTouchEvent: ACTION_UP old angle" + getAngle());
}
long clickDuration = Calendar.getInstance().getTimeInMillis() - startClickTime;
if (clickDuration > 50) {
updateOnTouchForMove(event);
} else {
updateOnTouch(event);
}
setPressed(false);
this.getParent().requestDisallowInterceptTouchEvent(false);
break;
case MotionEvent.ACTION_CANCEL:
onStopTrackingTouch();
setPressed(false);
this.getParent().requestDisallowInterceptTouchEvent(false);
break;
}
return true;
}
return false;
}
private boolean ignoreAngleTouch(float x, float y) {
boolean ignore = false;
double touchAngle = getTouchDegrees(x, y);
if (touchAngle > START_ANGLE && touchAngle < LOWER_THRESHOLD_VALUE || touchAngle > START_ANGLE && touchAngle < THRESHOLD_VALUE) {
if (Util.IS_DEBUG_LOGGABLE) {
Log.d(TAG, "ignoreAngleTouch");
}
ignore = true;
}
return ignore;
}
private void updateOnTouchForMove(MotionEvent event) {
setPressed(true);
mTouchAngle = getTouchDegrees(event.getX(), event.getY());
if (Util.IS_DEBUG_LOGGABLE) {
Log.d(TAG, "Touch Angle " + mTouchAngle);
}
int angle = (int) mTouchAngle - (int) START_ANGLE;
updateAngleForMove(angle);
}
private void updateAngleForMove(int angle) {
mAngle = (angle > MAX) ? angle : (angle < 0) ? angle : angle;
if (angle == 0) {
mAngle = (int) START_ANGLE;
}
int cloneAngle = mAngle;
if (mTouchAngle > START_ANGLE && mTouchAngle < LOWER_THRESHOLD_VALUE) {
mAngle = LOWER_LIMIT;
}
if ((mAngle / 13) > 19) {
mAngle = COMPLETE_ANGLE;
}
if (mOnProtractorViewChangeListener != null) {
mOnProtractorViewChangeListener.onProgressChanged(this, cloneAngle, true);
}
boolean check = mTouchAngle > START_ANGLE && mTouchAngle < THRESHOLD_VALUE;
if (!check) {
updateThumbPosition();
if (Util.IS_DEBUG_LOGGABLE) {
Log.d(TAG, "updateAngle: Re Drawing");
}
invalidate();
} else {
if (Util.IS_DEBUG_LOGGABLE) {
Log.d(TAG, "Inside else condition");
}
mAngle = LOWER_LIMIT;
updateThumbPosition();
invalidate();
}
}
private void onStartTrackingTouch() {
if (mOnProtractorViewChangeListener != null) {
mOnProtractorViewChangeListener.onStartTrackingTouch(this);
}
}
private void onStopTrackingTouch() {
if (mOnProtractorViewChangeListener != null) {
mOnProtractorViewChangeListener.onStopTrackingTouch(this);
}
}
private boolean ignoreTouch(float xPos, float yPos) {
boolean ignore = false;
float x = xPos - mTranslateX;
float y = yPos - mTranslateY;
float touchRadius = (float) Math.sqrt(((x * x) + (y * y)));
if (touchRadius < mTouchIgnoreRadius + 30 || touchRadius > (mArcRadius + mTickLength + mTickOffset)) {
ignore = true;
}
return ignore;
}
private void updateOnTouch(MotionEvent event) {
if (Util.IS_DEBUG_LOGGABLE) {
Log.d(TAG, "updateOnTouch: Old Angle" + getAngle());
}
boolean ignoreTouch = ignoreTouch(event.getX(), event.getY());
if (ignoreTouch) {
if (Util.IS_DEBUG_LOGGABLE) {
Log.d(TAG, "in ignore touch");
}
return;
}
setPressed(true);
mTouchAngle = getTouchDegrees(event.getX(), event.getY());
if (Util.IS_DEBUG_LOGGABLE) {
Log.d(TAG, "Touch Angle " + mTouchAngle);
}
int angle = (int) mTouchAngle - (int) START_ANGLE;
onProgressRefresh(angle, true);
}
private double getTouchDegrees(float xPos, float yPos) {
float x = xPos - mTranslateX;
float y = yPos - mTranslateY;
x = -x;
// convert to arc Angle
double angle = Math.toDegrees(Math.atan2(y, x) + (Math.PI));
/*if (angle > 270)
angle = 0;
else if (angle > 180)
angle = 360;*/
return angle;
}
private void onProgressRefresh(int angle, boolean fromUser) {
if (Util.IS_DEBUG_LOGGABLE) {
Log.d(TAG, "Change Angle: " + angle);
}
updateAngle(angle, fromUser);
}
private void updateAngle(int angle, boolean fromUser) {
if (Util.IS_DEBUG_LOGGABLE) {
Log.d(TAG, "updateAngle: " + angle);
}
mAngle = (angle > MAX) ? angle : (angle < 0) ? angle : angle;
if (angle == 0) {
mAngle = (int) START_ANGLE;
}
if (mAngle > LOWER_LIMIT && mAngle < 0) {
mAngle = LOWER_LIMIT;
}
if (mTouchAngle > START_ANGLE && mTouchAngle < THRESHOLD_VALUE) {
mAngle = LOWER_LIMIT;
}
int cloneAngle = mAngle;
if (mAngle > 0) {
cloneAngle = mAngle - 360;
}
if ((mAngle / 13) > 19) {
mAngle = COMPLETE_ANGLE;
}
if (Util.IS_DEBUG_LOGGABLE) {
Log.d(TAG, "updateAngle: Angle being sent to onProgressChanged " + cloneAngle);
}
if (mOnProtractorViewChangeListener != null) {
mOnProtractorViewChangeListener.onProgressChanged(this, cloneAngle, true);
}
if (Util.IS_DEBUG_LOGGABLE) {
Log.d(TAG, "Angle being sent to the function = " + mAngle);
}
if (Util.IS_DEBUG_LOGGABLE) {
Log.d(TAG, "Value of Sweep Angle " + sweepAngle);
}
boolean check = mTouchAngle > START_ANGLE && mTouchAngle < THRESHOLD_VALUE;
if (Util.IS_DEBUG_LOGGABLE) {
Log.d(TAG, "Check Condition Value: " + check);
}
if (!check) {
updateThumbPosition();
if (Util.IS_DEBUG_LOGGABLE) {
Log.d(TAG, "updateAngle: Re Drawing");
}
startAnimatingArc();
} else {
mAngle = LOWER_LIMIT;
updateThumbPosition();
startAnimatingArc();
}
}
public void startAnimatingArc() {
final ProtractorView protractorView = findViewById(R.id.protractorview);
if (Util.IS_DEBUG_LOGGABLE) {
Log.d(TAG, "Inside start Animating Arc\nOld Angle: " + getOldAngle() + "\nNew Angle: " + getAngle());
}
int newAngle = getAngle();
if (newAngle > 0) {
newAngle -= 360;
}
ValueAnimator animator = ValueAnimator.ofInt(getOldAngle(), newAngle);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int animatedValue = (int) animation.getAnimatedValue();
if (Util.IS_DEBUG_LOGGABLE) {
Log.d(TAG, "onAnimationUpdate: Animated Value " + animatedValue);
}
mAngle = animatedValue;
protractorView.invalidate();
}
});
animator.setDuration(450);
animator.start();
// invalidate();
}
private void updateThumbPosition() {
int thumbAngle = mAngle; //(int) (mStartAngle + mProgressSweep + mRotation + 90);
mThumbXPos = (int)(mArcRadius * Math.cos(Math.toRadians(thumbAngle)));
mThumbYPos = (int)(mArcRadius * Math.sin(Math.toRadians(thumbAngle)));
}
//*****************************************************
// Setters and Getters
//*****************************************************
public boolean getTouchInside() {
return mTouchInside;
}
public void setTouchInside(boolean isEnabled) {
int thumbHalfheight = mThumb.getIntrinsicHeight() / 2;
int thumbHalfWidth = mThumb.getIntrinsicWidth() / 2;
mTouchInside = isEnabled;
if (mTouchInside) {
mTouchIgnoreRadius = (float)(mArcRadius / 1.5) + 5;
} else {
mTouchIgnoreRadius = mArcRadius + 5 - Math.min(thumbHalfWidth, thumbHalfheight);
}
}
public void setOnProtractorViewChangeListener(OnProtractorViewChangeListener l) {
mOnProtractorViewChangeListener = l;
}
public OnProtractorViewChangeListener getOnProtractorViewChangeListener() {
return mOnProtractorViewChangeListener;
}
public int getAngle() {
return mAngle;
}
public void setAngle(int angle) {
this.mAngle = angle;
onProgressRefresh(mAngle, false);
}
public int getOldAngle() {
return oldAngle;
}
public boolean isEnabled() {
return mEnabled;
}
public void setEnabled(boolean enabled) {
this.mEnabled = enabled;
invalidate();
}
public int getProgressColor() {
return mArcProgressPaint.getColor();
}
public void setProgressColor(@ColorInt int color) {
mArcProgressPaint.setColor(color);
invalidate();
}
public int getArcColor() {
return mArcPaint.getColor();
}
public void setArcColor(@ColorInt int color) {
mArcPaint.setColor(color);
invalidate();
}
public int getArcProgressWidth() {
return mArcProgressWidth;
}
public void setArcProgressWidth(int arcProgressWidth) {
this.mArcProgressWidth = arcProgressWidth;
mArcProgressPaint.setStrokeWidth(arcProgressWidth);
invalidate();
}
public int getArcWidth() {
return mArcWidth;
}
public void setArcWidth(int arcWidth) {
this.mArcWidth = arcWidth;
mArcPaint.setStrokeWidth(arcWidth);
invalidate();
}
public boolean isRoundedEdges() {
return mRoundedEdges;
}
public void setRoundedEdges(boolean roundedEdges) {
this.mRoundedEdges = roundedEdges;
if (roundedEdges) {
mArcPaint.setStrokeCap(Paint.Cap.ROUND);
mArcProgressPaint.setStrokeCap(Paint.Cap.ROUND);
} else {
mArcPaint.setStrokeCap(Paint.Cap.SQUARE);
mArcPaint.setStrokeCap(Paint.Cap.SQUARE);
}
invalidate();
}
public Drawable getThumb() {
return mThumb;
}
public void setThumb(Drawable thumb) {
this.mThumb = thumb;
invalidate();
}
public int getAngleTextSize() {
return mAngleTextSize;
}
public void setAngleTextSize(int angleTextSize) {
this.mAngleTextSize = angleTextSize;
invalidate();
}
public int getTickOffset() {
return mTickOffset;
}
public void setTickOffset(int tickOffset) {
this.mTickOffset = tickOffset;
}
public int getTickLength() {
return mTickLength;
}
public void setTickLength(int tickLength) {
this.mTickLength = tickLength;
}
public TicksBetweenLabel getTicksBetweenLabel() {
return mTicksBetweenLabel;
}
public void setTicksBetweenLabel(TicksBetweenLabel ticksBetweenLabel) {
this.mTicksBetweenLabel = mTicksBetweenLabel;
invalidate();
}
public int getTickIntervals() {
return mTickIntervals;
}
public void setTickIntervals(int tickIntervals) {
this.mTickIntervals = tickIntervals;
invalidate();
}
}