package ca.josephroque.bowlingcompanion.view;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.OvershootInterpolator;
import android.view.animation.ScaleAnimation;
import ca.josephroque.bowlingcompanion.utilities.DisplayUtils;
/**
* A {@link android.support.design.widget.FloatingActionButton} which provides methods to animate changing the drawable
* and background colors.
*/
public class AnimatedFloatingActionButton
extends FloatingActionButton {
/** Identifies output from this class in Logcat. */
@SuppressWarnings("unused")
private static final String TAG = "AnimatedFab";
/** Current icon of the floating action button. */
private int mCurrentFabIcon = 0;
/** Current initial color of the floating action button. */
private int mCurrentFabDefaultColor = 0;
/** Current pressed color of the floating action button. */
private int mCurrentFabPressedColor = 0;
/** Indicates if the floating action button is being animated. */
private boolean mFabIsAnimating = false;
/**
* Default constructor which only passes parameters to super constructor.
*
* @param context context the view is running in
*/
public AnimatedFloatingActionButton(Context context) {
super(context);
}
/**
* Default constructor which only passes parameters to super constructor.
*
* @param context context the view is running in
* @param attrs attributes of the XML tag inflating the view
*/
public AnimatedFloatingActionButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* Default constructor which only passes parameters to super constructor.
*
* @param context context the view is running in
* @param attrs attributes of the XML tag inflating the view
* @param defStyle attribute in the current theme that contains a reference to a style resource that supplies
* default values for the view
*/
public AnimatedFloatingActionButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean onTouchEvent(@NonNull MotionEvent event) {
// Overrides touch handler so that on click listener is not invoked if fab is animating
return !mFabIsAnimating && super.onTouchEvent(event);
}
/**
* Sets the icon and colors of the floating action button with animation.
*
* @param drawableId id of the drawable for the floating action button
* @param defaultColor standing color of the floating action button
* @param pressedColor pressed color of the floating action button
*/
public void animate(final int drawableId, final int defaultColor, final int pressedColor) {
if ((drawableId != mCurrentFabIcon || defaultColor != mCurrentFabDefaultColor
|| pressedColor != mCurrentFabPressedColor) || drawableId == 0) {
if (mCurrentFabIcon == 0 && drawableId != 0)
growFloatingActionButton(drawableId, defaultColor, pressedColor);
else
shrinkFloatingActionButton(drawableId, defaultColor, pressedColor);
}
}
/**
* Shrinks the floating action button.
*
* @param drawableId new drawable to set if fab grows again
* @param defaultColor standing color of the floating action button
* @param pressedColor pressed color of the floating action button
*/
private void shrinkFloatingActionButton(final int drawableId, final int defaultColor, final int pressedColor) {
if (getVisibility() == View.GONE) {
mCurrentFabIcon = drawableId;
return;
}
final int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);
ScaleAnimation shrink = new ScaleAnimation(1.0f,
0f,
1.0f,
0f,
Animation.RELATIVE_TO_SELF,
DisplayUtils.ANIMATION_CENTER_PIVOT,
Animation.RELATIVE_TO_SELF,
DisplayUtils.ANIMATION_CENTER_PIVOT);
shrink.setDuration((mCurrentFabIcon == 0)
? 1
: shortAnimTime);
shrink.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
mFabIsAnimating = true;
}
@Override
public void onAnimationEnd(Animation animation) {
mFabIsAnimating = false;
growFloatingActionButton(drawableId, defaultColor, pressedColor);
}
@Override
public void onAnimationRepeat(Animation animation) {
// does nothing
}
});
startAnimation(shrink);
}
/**
* Grows the floating action button.
*
* @param drawableId new drawable to set
* @param defaultColor standing color of the floating action button
* @param pressedColor pressed color of the floating action button
*/
private void growFloatingActionButton(final int drawableId, final int defaultColor, final int pressedColor) {
final int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);
mCurrentFabIcon = drawableId;
if (mCurrentFabIcon != 0)
setVisibility(View.VISIBLE);
else {
setVisibility(View.GONE);
return;
}
// Update the icon and colors of the fab as necessary
setIcon(mCurrentFabIcon);
if (mCurrentFabDefaultColor != defaultColor || mCurrentFabPressedColor != pressedColor) {
mCurrentFabDefaultColor = defaultColor;
mCurrentFabPressedColor = pressedColor;
DisplayUtils.setFloatingActionButtonColors(this, mCurrentFabDefaultColor, mCurrentFabPressedColor);
}
ScaleAnimation grow = new ScaleAnimation(0f,
1.0f,
0f,
1.0f,
Animation.RELATIVE_TO_SELF,
DisplayUtils.ANIMATION_CENTER_PIVOT,
Animation.RELATIVE_TO_SELF,
DisplayUtils.ANIMATION_CENTER_PIVOT);
grow.setDuration(shortAnimTime);
grow.setInterpolator(new OvershootInterpolator());
grow.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
mFabIsAnimating = true;
}
@Override
public void onAnimationEnd(Animation animation) {
mFabIsAnimating = false;
}
@Override
public void onAnimationRepeat(Animation animation) {
// does nothing
}
});
startAnimation(grow);
}
/**
* Sets a new icon for the floating action button.
*
* @param drawableId id of the icon drawable
*/
private void setIcon(int drawableId) {
setImageResource(drawableId);
Drawable drawable = getDrawable();
if (drawable != null) {
drawable.mutate();
drawable.setAlpha(DisplayUtils.BLACK_ICON_ALPHA);
}
}
}