Android 线路径变形动画
Android line path morphing animation
我基本上有两条线,由我 canvas 上的两条路径绘制。每个人只有两个点,一个应该保持静止,另一个应该移动。我只是通过创建一个 Path 然后调用 moveTo(x1, y1) 和 lineTo(x2, y2).
来实现这一点
(x1, y1) 不会随时间变化,想实现(x2, y2) 变化时的动画
这是我现在的代码:
public class ProgressDownload extends View {
private static final String LOG_TAG = ProgressDownload.class.getSimpleName();
private static final int STROKE_WIDTH = 10;
private static final int PADDING = 50;
private static final String BACKGROUND_COLOR = "#EC5745";
private int mWidth, mHeight;
private int mProgress;
private Path mPathBlack, mPathWhite;
private Paint mPaintBlack, mPaintWhite;
private PathEffect mPathBlackEffect, mPathWhiteEffect;
public ProgressDownload(Context context, AttributeSet attrs) {
super(context, attrs);
setBackgroundColor(Color.parseColor(BACKGROUND_COLOR));
setPadding(PADDING, 0, 50, PADDING);
mPaintBlack = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintBlack.setStyle(Paint.Style.STROKE);
mPaintBlack.setStrokeWidth(STROKE_WIDTH);
mPaintBlack.setColor(Color.BLACK);
mPaintWhite = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintWhite.setStyle(Paint.Style.STROKE);
mPaintWhite.setStrokeWidth(STROKE_WIDTH);
mPaintWhite.setColor(Color.WHITE);
mPathBlackEffect = new CornerPathEffect(10);
mPathWhiteEffect = new CornerPathEffect(10);
}
@Override
protected void onDraw(Canvas canvas) {
if(mPathWhite != null && mPathBlack != null) {
mPaintBlack.setPathEffect(mPathBlackEffect);
mPaintWhite.setPathEffect(mPathWhiteEffect);
canvas.drawPath(mPathBlack, mPaintBlack);
canvas.drawPath(mPathWhite, mPaintWhite);
}
}
@Override
protected void onSizeChanged(int xNew, int yNew, int xOld, int yOld) {
super.onSizeChanged(xNew, yNew, xOld, yOld);
mWidth = xNew - getPaddingRight();
mHeight = yNew;
Log.d(LOG_TAG, String.format("width and height measured are %d and %d", mWidth, mHeight));
setPercentage(0);
}
private Path makePathBlack() {
Path p = new Path();
p.moveTo(Math.max(getPaddingLeft(), mProgress*mWidth/100), mHeight/2 + calculatedeltaY());
p.lineTo(mWidth, mHeight/2);
return p;
}
private Path makePathWhite() {
Path p = new Path();
p.moveTo(getPaddingLeft(), mHeight / 2);
p.lineTo(Math.max(getPaddingLeft(), mProgress*mWidth/100), mHeight/2 + calculatedeltaY());
return p;
}
private int calculatedeltaY() {
if(mProgress <= 50) {
return (mProgress * mWidth/6)/50;
} else {
return ((100-mProgress) * mWidth/6)/50;
}
}
public void setPercentage(int percentage) {
if(percentage < 0 || percentage > 100)
throw new IllegalArgumentException("setPercentage not between 0 and 100");
mProgress = percentage;
mPathBlack = makePathBlack();
mPathWhite = makePathWhite();
invalidate();
}
}
我看到了路径动画的多种可能性,我想我需要一些东西来将我当前的路径更新为新路径。
setPercentage() 这里根据传递的值更新两个路径。目前,新旧路径之间的转换有点 "brutal"。对此有何建议?
我突然开始研究对象动画师。解决方案是使用一个从当前百分比到新百分比的动画。结果正是我想要的。这是更新后的视图:
public class ProgressDownload extends View {
private static final String LOG_TAG = ProgressDownload.class.getSimpleName();
private static final int STROKE_WIDTH = 10;
private static final int PADDING = 50;
private static final long ANIMATION_DURATION = 1000;
private static final String BACKGROUND_COLOR = "#EC5745";
private int mWidth, mHeight;
private int mProgress = 0;
private Path mPathBlack, mPathWhite;
private Paint mPaintBlack, mPaintWhite;
private PathEffect mPathBlackEffect, mPathWhiteEffect;
public ProgressDownload(Context context, AttributeSet attrs) {
super(context, attrs);
setBackgroundColor(Color.parseColor(BACKGROUND_COLOR));
setPadding(PADDING, 0, 50, PADDING);
mPaintBlack = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintBlack.setStyle(Paint.Style.STROKE);
mPaintBlack.setStrokeWidth(STROKE_WIDTH);
mPaintBlack.setColor(Color.BLACK);
mPaintWhite = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintWhite.setStyle(Paint.Style.STROKE);
mPaintWhite.setStrokeWidth(STROKE_WIDTH);
mPaintWhite.setColor(Color.WHITE);
mPathBlackEffect = new CornerPathEffect(10);
mPathWhiteEffect = new CornerPathEffect(10);
}
@Override
protected void onDraw(Canvas canvas) {
if(mPathWhite != null && mPathBlack != null) {
mPaintBlack.setPathEffect(mPathBlackEffect);
mPaintWhite.setPathEffect(mPathWhiteEffect);
canvas.drawPath(mPathBlack, mPaintBlack);
canvas.drawPath(mPathWhite, mPaintWhite);
}
}
@Override
protected void onSizeChanged(int xNew, int yNew, int xOld, int yOld) {
super.onSizeChanged(xNew, yNew, xOld, yOld);
mWidth = xNew - getPaddingRight();
mHeight = yNew;
Log.d(LOG_TAG, String.format("width and height measured are %d and %d", mWidth, mHeight));
setPercentage(mProgress);
}
private Path makePathBlack() {
if(mPathBlack ==null) {
mPathBlack = new Path();
}
Path p = new Path();
p.moveTo(Math.max(getPaddingLeft(), mProgress*mWidth/100), mHeight/2 + calculatedeltaY());
p.lineTo(mWidth, mHeight/2);
mPathBlack.set(p);
return p;
}
private void makePathWhite() {
if(mPathWhite ==null) {
mPathWhite = new Path();
}
Path p = new Path();
p.moveTo(getPaddingLeft(), mHeight / 2);
p.lineTo(Math.max(getPaddingLeft(), mProgress * mWidth / 100), mHeight / 2 + calculatedeltaY());
mPathWhite.set(p);
}
private int calculatedeltaY() {
if(mProgress <= 50) {
return (mProgress * mWidth/6)/50;
} else {
return ((100-mProgress) * mWidth/6)/50;
}
}
public void setPercentage(int newProgress) {
if(newProgress < 0 || newProgress > 100)
throw new IllegalArgumentException("setPercentage not between 0 and 100");
ObjectAnimator anim = ObjectAnimator.ofInt(this, "progress", getProgress(), newProgress);
anim.setDuration(ANIMATION_DURATION);
anim.setInterpolator(new LinearInterpolator());
anim.start();
}
public void setProgress(int progress) {
mProgress = progress;
makePathBlack();
makePathWhite();
invalidate();
}
public int getProgress() {
return mProgress;
}
}
我基本上有两条线,由我 canvas 上的两条路径绘制。每个人只有两个点,一个应该保持静止,另一个应该移动。我只是通过创建一个 Path 然后调用 moveTo(x1, y1) 和 lineTo(x2, y2).
来实现这一点(x1, y1) 不会随时间变化,想实现(x2, y2) 变化时的动画
这是我现在的代码:
public class ProgressDownload extends View {
private static final String LOG_TAG = ProgressDownload.class.getSimpleName();
private static final int STROKE_WIDTH = 10;
private static final int PADDING = 50;
private static final String BACKGROUND_COLOR = "#EC5745";
private int mWidth, mHeight;
private int mProgress;
private Path mPathBlack, mPathWhite;
private Paint mPaintBlack, mPaintWhite;
private PathEffect mPathBlackEffect, mPathWhiteEffect;
public ProgressDownload(Context context, AttributeSet attrs) {
super(context, attrs);
setBackgroundColor(Color.parseColor(BACKGROUND_COLOR));
setPadding(PADDING, 0, 50, PADDING);
mPaintBlack = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintBlack.setStyle(Paint.Style.STROKE);
mPaintBlack.setStrokeWidth(STROKE_WIDTH);
mPaintBlack.setColor(Color.BLACK);
mPaintWhite = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintWhite.setStyle(Paint.Style.STROKE);
mPaintWhite.setStrokeWidth(STROKE_WIDTH);
mPaintWhite.setColor(Color.WHITE);
mPathBlackEffect = new CornerPathEffect(10);
mPathWhiteEffect = new CornerPathEffect(10);
}
@Override
protected void onDraw(Canvas canvas) {
if(mPathWhite != null && mPathBlack != null) {
mPaintBlack.setPathEffect(mPathBlackEffect);
mPaintWhite.setPathEffect(mPathWhiteEffect);
canvas.drawPath(mPathBlack, mPaintBlack);
canvas.drawPath(mPathWhite, mPaintWhite);
}
}
@Override
protected void onSizeChanged(int xNew, int yNew, int xOld, int yOld) {
super.onSizeChanged(xNew, yNew, xOld, yOld);
mWidth = xNew - getPaddingRight();
mHeight = yNew;
Log.d(LOG_TAG, String.format("width and height measured are %d and %d", mWidth, mHeight));
setPercentage(0);
}
private Path makePathBlack() {
Path p = new Path();
p.moveTo(Math.max(getPaddingLeft(), mProgress*mWidth/100), mHeight/2 + calculatedeltaY());
p.lineTo(mWidth, mHeight/2);
return p;
}
private Path makePathWhite() {
Path p = new Path();
p.moveTo(getPaddingLeft(), mHeight / 2);
p.lineTo(Math.max(getPaddingLeft(), mProgress*mWidth/100), mHeight/2 + calculatedeltaY());
return p;
}
private int calculatedeltaY() {
if(mProgress <= 50) {
return (mProgress * mWidth/6)/50;
} else {
return ((100-mProgress) * mWidth/6)/50;
}
}
public void setPercentage(int percentage) {
if(percentage < 0 || percentage > 100)
throw new IllegalArgumentException("setPercentage not between 0 and 100");
mProgress = percentage;
mPathBlack = makePathBlack();
mPathWhite = makePathWhite();
invalidate();
}
}
我看到了路径动画的多种可能性,我想我需要一些东西来将我当前的路径更新为新路径。
setPercentage() 这里根据传递的值更新两个路径。目前,新旧路径之间的转换有点 "brutal"。对此有何建议?
我突然开始研究对象动画师。解决方案是使用一个从当前百分比到新百分比的动画。结果正是我想要的。这是更新后的视图:
public class ProgressDownload extends View {
private static final String LOG_TAG = ProgressDownload.class.getSimpleName();
private static final int STROKE_WIDTH = 10;
private static final int PADDING = 50;
private static final long ANIMATION_DURATION = 1000;
private static final String BACKGROUND_COLOR = "#EC5745";
private int mWidth, mHeight;
private int mProgress = 0;
private Path mPathBlack, mPathWhite;
private Paint mPaintBlack, mPaintWhite;
private PathEffect mPathBlackEffect, mPathWhiteEffect;
public ProgressDownload(Context context, AttributeSet attrs) {
super(context, attrs);
setBackgroundColor(Color.parseColor(BACKGROUND_COLOR));
setPadding(PADDING, 0, 50, PADDING);
mPaintBlack = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintBlack.setStyle(Paint.Style.STROKE);
mPaintBlack.setStrokeWidth(STROKE_WIDTH);
mPaintBlack.setColor(Color.BLACK);
mPaintWhite = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintWhite.setStyle(Paint.Style.STROKE);
mPaintWhite.setStrokeWidth(STROKE_WIDTH);
mPaintWhite.setColor(Color.WHITE);
mPathBlackEffect = new CornerPathEffect(10);
mPathWhiteEffect = new CornerPathEffect(10);
}
@Override
protected void onDraw(Canvas canvas) {
if(mPathWhite != null && mPathBlack != null) {
mPaintBlack.setPathEffect(mPathBlackEffect);
mPaintWhite.setPathEffect(mPathWhiteEffect);
canvas.drawPath(mPathBlack, mPaintBlack);
canvas.drawPath(mPathWhite, mPaintWhite);
}
}
@Override
protected void onSizeChanged(int xNew, int yNew, int xOld, int yOld) {
super.onSizeChanged(xNew, yNew, xOld, yOld);
mWidth = xNew - getPaddingRight();
mHeight = yNew;
Log.d(LOG_TAG, String.format("width and height measured are %d and %d", mWidth, mHeight));
setPercentage(mProgress);
}
private Path makePathBlack() {
if(mPathBlack ==null) {
mPathBlack = new Path();
}
Path p = new Path();
p.moveTo(Math.max(getPaddingLeft(), mProgress*mWidth/100), mHeight/2 + calculatedeltaY());
p.lineTo(mWidth, mHeight/2);
mPathBlack.set(p);
return p;
}
private void makePathWhite() {
if(mPathWhite ==null) {
mPathWhite = new Path();
}
Path p = new Path();
p.moveTo(getPaddingLeft(), mHeight / 2);
p.lineTo(Math.max(getPaddingLeft(), mProgress * mWidth / 100), mHeight / 2 + calculatedeltaY());
mPathWhite.set(p);
}
private int calculatedeltaY() {
if(mProgress <= 50) {
return (mProgress * mWidth/6)/50;
} else {
return ((100-mProgress) * mWidth/6)/50;
}
}
public void setPercentage(int newProgress) {
if(newProgress < 0 || newProgress > 100)
throw new IllegalArgumentException("setPercentage not between 0 and 100");
ObjectAnimator anim = ObjectAnimator.ofInt(this, "progress", getProgress(), newProgress);
anim.setDuration(ANIMATION_DURATION);
anim.setInterpolator(new LinearInterpolator());
anim.start();
}
public void setProgress(int progress) {
mProgress = progress;
makePathBlack();
makePathWhite();
invalidate();
}
public int getProgress() {
return mProgress;
}
}