Android:以编程方式为自定义 Drawable 设置动画
Android: Animate Custom Drawable programmatically
我有一个自定义 Class 扩展 Drawable 如下所示,它用于绘制弧形。从控制 Drawable 的 MainActivity 中,我根据一些输入值重绘它,我将这些输入值转换为形状的适当 "angle"。例如
这是可绘制对象的初始状态:
这是可绘制对象的第二种状态:
红色箭头表示我要实现的动作
我正在尝试 "animate" 从状态 1 到状态 2 的变化是一个扫过的动作。关于如何做到这一点的任何想法?我是否应该在状态一和状态二之间逐渐过渡多次重绘形状?
我的绘图代码:
public class CircleLoadingBar extends Drawable implements Drawable.Callback{
private Paint paint;
private Canvas canvas;
private float angle;
private RectF outterCircle;
private float padding=30;
public void invalidateDrawable(Drawable drawable){
final Callback callback = getCallback();
if (callback != null) {
callback.invalidateDrawable(this);
}
}
public void scheduleDrawable(Drawable drawable, Runnable runnable, long l){
invalidateDrawable(drawable);
}
public void unscheduleDrawable(Drawable drawable,Runnable runnable){
//empty
}
public CircleLoadingBar(){
this(0);
}
public CircleLoadingBar( int angle){
this.angle=angle;
this.canvas=new Canvas();
paint=new Paint();
paint.setColor(Color.GREEN);
paint.setStrokeWidth(padding);
paint.setAntiAlias(true);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStyle(Paint.Style.STROKE);
outterCircle = new RectF();
}
public void setAngle(float angle){
this.angle=angle;
}
@Override
public void draw(Canvas canvas){
canvas.save();
Rect bounds = getBounds();
outterCircle.set(bounds.left+padding,bounds.top+padding,bounds.right-padding,bounds.bottom-padding);
int[] colors = {Color.RED, Color.GREEN, Color.RED};
float[] positions = {0,0.2f,1.3f};
SweepGradient gradient3 = new SweepGradient(innerCircle.centerX(), innerCircle.centerY(),colors,positions);
paint.setShader(gradient3);
canvas.drawArc(outterCircle,90,angle,true,paint);
}
@Override
public void setAlpha(int alpha) {
// Has no effect
}
@Override
public void setColorFilter(ColorFilter cf) {
// Has no effect
}
@Override
public int getOpacity() {
// Not Implemented
return 0;
}
}
我的 MainActivity 代码:
public class MainActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate();
setContentView(R.layout.main);
textView= (TextView) findViewById(R.id.textview);
circleLoadingBar= new CircleLoadingBar(10);
textView.setBackgroundDrawable(circleLoadingBar);
}
public void stateUpdate(float angle) {
circleLoadingBar.setAngle(angle);
textView.invalidate();
}
}
经过大量搜索,我找到了答案。
总结:
我需要我的 Custom Drawable class 来实现 Drawable.Callback 和 Runnable 接口(见下面的代码)。
CustomDrawable.class
public class CustomDrawable extends Drawable implements Drawable.Callback, Runnable{
private Paint paint;
private Canvas canvas;
private int angle;
private RectF circle;
private float cx,cy;
private float mHeight,mWidth=100;
private float mRadius=20;
private Drawable.Callback cb;
private boolean running=false;
public void invalidateDrawable(Drawable drawable){
super.invalidateSelf(); //This was done for my specific example. I wouldn't use it otherwise
}
public void scheduleDrawable(Drawable drawable, Runnable runnable, long l){
invalidateDrawable(drawable);
}
public void unscheduleDrawable(Drawable drawable,Runnable runnable){
super.unscheduleSelf(runnable);
}
public CircleLoadingBar(){
this(0);
}
public CircleLoadingBar(int angle){
this.angle=angle;
paint=new Paint();
paint.setColor(Color.GREEN);
paint.setAntiAlias(true);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStyle(Paint.Style.STROKE);
circle= new RectF();
}
@Override
public void draw(Canvas canvas){
canvas.save();
Rect bounds = getBounds();
circle.set(bounds);
canvas.drawArc(circle, 90, angle, true, paint);
}
public void nextFrame(){
unscheduleSelf(this);
scheduleSelf(this, SystemClock.uptimeMillis() + 250);
}
public void stop(){
running=false;
unscheduleSelf(this);
}
public void start(){
if(!running){
running=true;
nextFrame();
}
}
public void run(){
angle++;
invalidate();
nextFrame();
}
@Override
public void setAlpha(int alpha) {
// Has no effect
}
@Override
public void setColorFilter(ColorFilter cf) {
// Has no effect
}
@Override
public int getOpacity() {
// Not Implemented
return 0;
}
}
现在您的 Drawable 实现了两者,您可以 "run" 它作为一个单独的线程,由您的 activity 通过启动和停止功能启动和控制。
我有一个自定义 Class 扩展 Drawable 如下所示,它用于绘制弧形。从控制 Drawable 的 MainActivity 中,我根据一些输入值重绘它,我将这些输入值转换为形状的适当 "angle"。例如
这是可绘制对象的初始状态:
这是可绘制对象的第二种状态:
我正在尝试 "animate" 从状态 1 到状态 2 的变化是一个扫过的动作。关于如何做到这一点的任何想法?我是否应该在状态一和状态二之间逐渐过渡多次重绘形状?
我的绘图代码:
public class CircleLoadingBar extends Drawable implements Drawable.Callback{
private Paint paint;
private Canvas canvas;
private float angle;
private RectF outterCircle;
private float padding=30;
public void invalidateDrawable(Drawable drawable){
final Callback callback = getCallback();
if (callback != null) {
callback.invalidateDrawable(this);
}
}
public void scheduleDrawable(Drawable drawable, Runnable runnable, long l){
invalidateDrawable(drawable);
}
public void unscheduleDrawable(Drawable drawable,Runnable runnable){
//empty
}
public CircleLoadingBar(){
this(0);
}
public CircleLoadingBar( int angle){
this.angle=angle;
this.canvas=new Canvas();
paint=new Paint();
paint.setColor(Color.GREEN);
paint.setStrokeWidth(padding);
paint.setAntiAlias(true);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStyle(Paint.Style.STROKE);
outterCircle = new RectF();
}
public void setAngle(float angle){
this.angle=angle;
}
@Override
public void draw(Canvas canvas){
canvas.save();
Rect bounds = getBounds();
outterCircle.set(bounds.left+padding,bounds.top+padding,bounds.right-padding,bounds.bottom-padding);
int[] colors = {Color.RED, Color.GREEN, Color.RED};
float[] positions = {0,0.2f,1.3f};
SweepGradient gradient3 = new SweepGradient(innerCircle.centerX(), innerCircle.centerY(),colors,positions);
paint.setShader(gradient3);
canvas.drawArc(outterCircle,90,angle,true,paint);
}
@Override
public void setAlpha(int alpha) {
// Has no effect
}
@Override
public void setColorFilter(ColorFilter cf) {
// Has no effect
}
@Override
public int getOpacity() {
// Not Implemented
return 0;
}
}
我的 MainActivity 代码:
public class MainActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate();
setContentView(R.layout.main);
textView= (TextView) findViewById(R.id.textview);
circleLoadingBar= new CircleLoadingBar(10);
textView.setBackgroundDrawable(circleLoadingBar);
}
public void stateUpdate(float angle) {
circleLoadingBar.setAngle(angle);
textView.invalidate();
}
}
经过大量搜索,我找到了答案。
总结: 我需要我的 Custom Drawable class 来实现 Drawable.Callback 和 Runnable 接口(见下面的代码)。
CustomDrawable.class
public class CustomDrawable extends Drawable implements Drawable.Callback, Runnable{
private Paint paint;
private Canvas canvas;
private int angle;
private RectF circle;
private float cx,cy;
private float mHeight,mWidth=100;
private float mRadius=20;
private Drawable.Callback cb;
private boolean running=false;
public void invalidateDrawable(Drawable drawable){
super.invalidateSelf(); //This was done for my specific example. I wouldn't use it otherwise
}
public void scheduleDrawable(Drawable drawable, Runnable runnable, long l){
invalidateDrawable(drawable);
}
public void unscheduleDrawable(Drawable drawable,Runnable runnable){
super.unscheduleSelf(runnable);
}
public CircleLoadingBar(){
this(0);
}
public CircleLoadingBar(int angle){
this.angle=angle;
paint=new Paint();
paint.setColor(Color.GREEN);
paint.setAntiAlias(true);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStyle(Paint.Style.STROKE);
circle= new RectF();
}
@Override
public void draw(Canvas canvas){
canvas.save();
Rect bounds = getBounds();
circle.set(bounds);
canvas.drawArc(circle, 90, angle, true, paint);
}
public void nextFrame(){
unscheduleSelf(this);
scheduleSelf(this, SystemClock.uptimeMillis() + 250);
}
public void stop(){
running=false;
unscheduleSelf(this);
}
public void start(){
if(!running){
running=true;
nextFrame();
}
}
public void run(){
angle++;
invalidate();
nextFrame();
}
@Override
public void setAlpha(int alpha) {
// Has no effect
}
@Override
public void setColorFilter(ColorFilter cf) {
// Has no effect
}
@Override
public int getOpacity() {
// Not Implemented
return 0;
}
}
现在您的 Drawable 实现了两者,您可以 "run" 它作为一个单独的线程,由您的 activity 通过启动和停止功能启动和控制。