0

I'm having trouble with a simple alpha animation of a drawable. Bellow you have a test project which illustrates the problem.

Class that holds a ShapeDrawable

public class CustomDrawable {

public ShapeDrawable shapeDrawable;

public CustomDrawable(int left, int top, int right, int bottom, int color) {
    shapeDrawable = new ShapeDrawable(new RectShape());
    shapeDrawable.setBounds(new Rect(left, top, right, bottom));
    shapeDrawable.getPaint().setStyle(Paint.Style.FILL_AND_STROKE);
    shapeDrawable.getPaint().setColor(Color.BLUE);
}

public ShapeDrawable getShapeDrawable() {
    return shapeDrawable;
}

}

A custom view

public class CustomView extends View {

private CustomDrawable drawable;

public CustomView(Context context, AttributeSet attrs) {
    super(context, attrs);
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    drawable.getShapeDrawable().draw(canvas);
}

public void animateDrawable() {
    ValueAnimator va = ValueAnimator.ofInt(255, 0);
    va.setDuration(1000);
    va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        int alpha;
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            alpha = (int) animation.getAnimatedValue();
            drawable.getShapeDrawable().setAlpha(alpha);
            drawable.getShapeDrawable().getPaint().setAlpha(alpha);

            // This works but invalidates the whole view...
            //postInvalidate();
        }
    });
    va.start();
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    drawable = new CustomDrawable(0, 0, h/2, w/2, Color.MAGENTA);
}
}

Activity

public class MainActivity extends AppCompatActivity {
private final static String TAG = "MainActivity";
private CustomView customView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    customView = (CustomView) findViewById(R.id.customView);
    Button fadeOutBtn = (Button) findViewById(R.id.fadeOut);
    fadeOutBtn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            customView.animateDrawable();
        }
    });

}

}

If I don't call postnvalidate() in animateDrawable then there's no animation. Seeing other examples (non complete) it seems that the shape drawable should be animated only by using an animator, no need to manually call postInvalidate() in the view...

So, is my understanding correct, do I need to invalidate the whole view myself? And if that is the case will the whole view be "repainted" or just the dirty region?

Thanks

manfcas
  • 1,933
  • 7
  • 28
  • 47
Stelios
  • 11
  • 3
  • I may be missing something, but I think your implementation should be correct. Are you testing on a device or emulator? If device: Are animations turned off in the device? If so, turn animations on. Go to Settings > About phone, then tap on Build number 7 times. Hit Back, then click on Developer options. Somewhere there should be the check boxes for Window/Transition Animations. Make sure they're checked. – Noel Bautista Dec 23 '16 at 21:45
  • just do: `ShapeDrawable sd = new ShapeDrawable(new RectShape()); /* change some props of sd like style, color etc */ setBackground(sd);` – pskink Dec 24 '16 at 08:18
  • @pskink so I need to do setBackground for the animation to work? Is it this the intended use? – Stelios Dec 24 '16 at 13:42
  • @NoelBautista animation are turned on. I know since this works if I uncomment the postInvalidate() line... – Stelios Dec 24 '16 at 13:43
  • @pskink Btw it works if I do setBackground but what if I have multiple drawables I want to animate? – Stelios Dec 24 '16 at 13:46
  • animation works just fine, add some `Log.d` calls inside `onAnimationUpdate` and you will see it is called as time goes by, but in order to see the effect your view has to be `invalidate()`d – pskink Dec 24 '16 at 13:47
  • ok so if you have multiple `Drawable`s then, yes, you have to draw them as you do now – pskink Dec 24 '16 at 13:48
  • but honestly: isnt it easier to draw the stuff directly using `Canvas` API inside `onDraw` rather that using those `RectShape`s? – pskink Dec 24 '16 at 14:04
  • Well, if it is that you have to call `postInvalidate()`, then you should use this overloaded method which takes the bounds to invalidate, here you should pass the area of your drawable and then only that much part will get invalidated. postInvalidate(left, top, right, bottom)(https://developer.android.com/reference/android/view/View.html#postInvalidate(int,%20int,%20int,%20int) – Samvid Mistry Dec 26 '16 at 15:27
  • I guess I didn't frame the question correctly... The ShapeDrawable calls invalidateSelf() in the setAlpha method (as seen in source). Should this not automatically result in the view being invalidated? – Stelios Dec 26 '16 at 20:24

0 Answers0