Reputation: 194
I'm trying to create a button-click animation, e.g. the button scales down a little when you press it, scales back up when you release. If you simply tap, you get the press and release strung together.
I set up an onTouchListener and a couple XML-defined AnimatorSets, one for the press and one for the release. Ran the press on ACTION_DOWN
, the release on ACTION_UP
or ACTION_CANCEL
. This works fine when you press and hold the button, then release a little later. But with a quick tap, the release animation triggers before the press one is done, and often the result is no animation at all.
I'd hoped I could use AnimatorSet's sequential capabilities to stick the release animation onto the end of the possibly-already-running press animation, but no luck. I'm sure I could rig something up with callbacks, but that seems messy.
What's the best approach here? Thanks!
Upvotes: 2
Views: 1991
Reputation: 2721
Looks like L Preview adds the ability to specify animations for state changes in the xml file.
https://developer.android.com/preview/material/animations.html#viewstate
Upvotes: 0
Reputation: 16761
I built a sample Button class that buffers animations and executes them in a queue according to what you need:
public class AnimationButton extends Button
{
private List<Animation> mAnimationBuffer = new ArrayList<Animation>();;
private boolean mIsAnimating;
public AnimationButton(Context context)
{
super(context);
}
public AnimationButton(Context context, AttributeSet attrs)
{
super(context, attrs);
}
public AnimationButton(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
}
@Override
public boolean onTouchEvent(MotionEvent event)
{
if (event.getAction() == MotionEvent.ACTION_DOWN)
{
generateAnimation(1, 0.75f);
triggerNextAnimation();
}
else if (event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_UP)
{
generateAnimation(0.75f, 1);
triggerNextAnimation();
}
return super.onTouchEvent(event);
}
private void generateAnimation(float from, float to)
{
ScaleAnimation scaleAnimation = new ScaleAnimation(from, to, from, to);
scaleAnimation.setFillAfter(true);
scaleAnimation.setDuration(500);
scaleAnimation.setAnimationListener(new ScaleAnimation.AnimationListener()
{
@Override
public void onAnimationStart(Animation animation) { }
@Override
public void onAnimationRepeat(Animation animation) { }
@Override
public void onAnimationEnd(Animation animation)
{
mIsAnimating = false;
triggerNextAnimation();
}
});
mAnimationBuffer.add(scaleAnimation);
}
private void triggerNextAnimation()
{
if (mAnimationBuffer.size() > 0 && !mIsAnimating)
{
mIsAnimating = true;
Animation currAnimation = mAnimationBuffer.get(0);
mAnimationBuffer.remove(0);
startAnimation(currAnimation);
}
}
}
Hope this helps :)
Upvotes: 5