diff --git a/README.md b/README.md
index 3e18bc0..465e97e 100644
--- a/README.md
+++ b/README.md
@@ -92,7 +92,13 @@ Here are all the **FloatingActionButton**'s xml attributes with their **default
app:fab_progress_indeterminate="false"
app:fab_progress_max="100"
app:fab_progress="0"
- app:fab_progress_showBackground="true"/>
+ app:fab_progress_showBackground="true"
+ fab:fab_icon_success="@drawable/your_drawable"
+ fab:fab_icon_failure="@drawable/your_drawable"
+ fab:fab_color_success="#84CA4B"
+ fab:fab_color_failure="#F8AE41"
+ fab:fab_success_failure_transition_animation_time="300"
+ fab:fab_success_failure_transition_animation_wait_time="2750"/>
```
All of these **FloatingActionButton**'s attributes has their corresponding getters and setters. So you can set them **programmatically**.
diff --git a/library/src/main/java/com/github/clans/fab/FloatingActionButton.java b/library/src/main/java/com/github/clans/fab/FloatingActionButton.java
index ea72dd2..deb0322 100755
--- a/library/src/main/java/com/github/clans/fab/FloatingActionButton.java
+++ b/library/src/main/java/com/github/clans/fab/FloatingActionButton.java
@@ -1,6 +1,9 @@
package com.github.clans.fab;
-import android.animation.LayoutTransition;
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ArgbEvaluator;
+import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.ColorStateList;
@@ -20,6 +23,7 @@
import android.graphics.drawable.RippleDrawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.StateListDrawable;
+import android.graphics.drawable.TransitionDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.graphics.drawable.shapes.Shape;
import android.os.Build;
@@ -32,7 +36,6 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
-import android.view.ViewParent;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageButton;
@@ -54,20 +57,29 @@ public class FloatingActionButton extends ImageButton {
private static final long PAUSE_GROWING_TIME = 200;
private static final double BAR_SPIN_CYCLE_TIME = 500;
private static final int BAR_MAX_LENGTH = 270;
+ private static final int DEFAULT_TRANSITION_ANIMATION_TIME = 300;
+ private static final int DEFAULT_TRANSITION_ANIMATION_WAIT_TIME = 2750;
private int mColorNormal;
private int mColorPressed;
private int mColorDisabled;
private int mColorRipple;
+ private int mColorSuccess;
+ private int mColorFailure;
private Drawable mIcon;
private int mIconSize = Util.dpToPx(getContext(), 24f);
private Animation mShowAnimation;
private Animation mHideAnimation;
+ private AnimatorSet mSuccessFailureStateAnimatorSet;
private String mLabelText;
private OnClickListener mClickListener;
private Drawable mBackgroundDrawable;
private boolean mUsingElevation;
private boolean mUsingElevationCompat;
+ private Drawable mSuccessDrawable;
+ private Drawable mFailureDrawable;
+ private int mSuccessFailureAnimationTime;
+ private int mSuccessFailureAnimationWaitTime;
// Progress
private boolean mProgressBarEnabled;
@@ -135,6 +147,12 @@ private void init(Context context, AttributeSet attrs, int defStyleAttr) {
mProgressBackgroundColor = attr.getColor(R.styleable.FloatingActionButton_fab_progress_backgroundColor, 0x4D000000);
mProgressMax = attr.getInt(R.styleable.FloatingActionButton_fab_progress_max, mProgressMax);
mShowProgressBackground = attr.getBoolean(R.styleable.FloatingActionButton_fab_progress_showBackground, true);
+ mSuccessDrawable = attr.getDrawable(R.styleable.FloatingActionButton_fab_icon_success);
+ mFailureDrawable = attr.getDrawable(R.styleable.FloatingActionButton_fab_icon_failure);
+ mColorSuccess = attr.getColor(R.styleable.FloatingActionButton_fab_color_success, 0xFF84CA4B);
+ mColorFailure = attr.getColor(R.styleable.FloatingActionButton_fab_color_failure, 0xFFF8AE41);
+ mSuccessFailureAnimationTime = attr.getInt(R.styleable.FloatingActionButton_fab_success_failure_transition_animation_time, DEFAULT_TRANSITION_ANIMATION_TIME);
+ mSuccessFailureAnimationWaitTime = attr.getInt(R.styleable.FloatingActionButton_fab_success_failure_transition_animation_wait_time, DEFAULT_TRANSITION_ANIMATION_WAIT_TIME);
if (attr.hasValue(R.styleable.FloatingActionButton_fab_progress)) {
mProgress = attr.getInt(R.styleable.FloatingActionButton_fab_progress, 0);
@@ -1295,4 +1313,80 @@ public void showButtonInMenu(boolean animate) {
label.show(animate);
}
}
+
+ public void animateFailure() {
+ animateFromToFrom(mIcon, mFailureDrawable, mColorNormal, mColorFailure);
+ }
+
+ public void animateSuccess() {
+ animateFromToFrom(mIcon, mSuccessDrawable, mColorNormal, mColorSuccess);
+ }
+
+ public boolean isSuccessOrFailureAnimationRunning() {
+ if (mSuccessFailureStateAnimatorSet != null && mSuccessFailureStateAnimatorSet.isRunning()) {
+ return true;
+ }
+ return false;
+ }
+
+ public void animateFromToFrom(Drawable animateFromDrawable,
+ Drawable animateToDrawable,
+ Integer colorFrom,
+ Integer colorTo) {
+ if (isSuccessOrFailureAnimationRunning()) {
+ return;
+ }
+ Drawable drawableStates[] = new Drawable[2];
+ drawableStates[0] = animateFromDrawable;
+ drawableStates[1] = animateToDrawable;
+ final TransitionDrawable transitionDrawable = new TransitionDrawable(drawableStates);
+ transitionDrawable.setCrossFadeEnabled(true);
+ setImageDrawable(transitionDrawable);
+
+ transitionDrawable.startTransition(mSuccessFailureAnimationTime);
+
+ ValueAnimator changeColorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
+ changeColorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animator) {
+ setColorNormal((Integer) animator.getAnimatedValue());
+ }
+ });
+ changeColorAnimation.setDuration(mSuccessFailureAnimationTime);
+
+ ValueAnimator doNothingAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
+ doNothingAnimation.setDuration(mSuccessFailureAnimationWaitTime);
+
+ ValueAnimator restoreColorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorTo, colorFrom);
+ restoreColorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animator) {
+ setColorNormal((Integer) animator.getAnimatedValue());
+ }
+ });
+ restoreColorAnimation.addListener(new Animator.AnimatorListener() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ transitionDrawable.reverseTransition(mSuccessFailureAnimationTime);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ setImageDrawable(transitionDrawable.getDrawable(0));
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ }
+ });
+ restoreColorAnimation.setDuration(mSuccessFailureAnimationTime);
+
+ mSuccessFailureStateAnimatorSet = new AnimatorSet();
+ mSuccessFailureStateAnimatorSet.playSequentially(changeColorAnimation, doNothingAnimation, restoreColorAnimation);
+ mSuccessFailureStateAnimatorSet.start();
+ }
}
diff --git a/library/src/main/res/values/attrs.xml b/library/src/main/res/values/attrs.xml
index 6348758..96390b6 100755
--- a/library/src/main/res/values/attrs.xml
+++ b/library/src/main/res/values/attrs.xml
@@ -25,6 +25,12 @@
+
+
+
+
+
+
diff --git a/sample/src/main/java/com/github/clans/fab/sample/RecyclerViewActivity.java b/sample/src/main/java/com/github/clans/fab/sample/RecyclerViewActivity.java
index b11c92d..68c5cf7 100644
--- a/sample/src/main/java/com/github/clans/fab/sample/RecyclerViewActivity.java
+++ b/sample/src/main/java/com/github/clans/fab/sample/RecyclerViewActivity.java
@@ -38,6 +38,7 @@ protected void onCreate(Bundle savedInstanceState) {
}
final FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
+ final FloatingActionButton loadingSuccessFab = (FloatingActionButton) findViewById(R.id.fab_loading_success);
fab.setMax(mMaxProgress);
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
@@ -92,6 +93,20 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
}
}
});
+
+ loadingSuccessFab.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ loadingSuccessFab.setIndeterminate(true);
+ new Handler().postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ loadingSuccessFab.animateSuccess();
+ loadingSuccessFab.setIndeterminate(false);
+ }
+ }, 1500);
+ }
+ });
}
private void increaseProgress(final FloatingActionButton fab, int i) {
diff --git a/sample/src/main/res/drawable-hdpi/ic_done.png b/sample/src/main/res/drawable-hdpi/ic_done.png
new file mode 100644
index 0000000..c278b6c
Binary files /dev/null and b/sample/src/main/res/drawable-hdpi/ic_done.png differ
diff --git a/sample/src/main/res/drawable-mdpi/ic_done.png b/sample/src/main/res/drawable-mdpi/ic_done.png
new file mode 100644
index 0000000..6d84e14
Binary files /dev/null and b/sample/src/main/res/drawable-mdpi/ic_done.png differ
diff --git a/sample/src/main/res/drawable-xhdpi/ic_done.png b/sample/src/main/res/drawable-xhdpi/ic_done.png
new file mode 100644
index 0000000..3b2b65d
Binary files /dev/null and b/sample/src/main/res/drawable-xhdpi/ic_done.png differ
diff --git a/sample/src/main/res/drawable-xxhdpi/ic_done.png b/sample/src/main/res/drawable-xxhdpi/ic_done.png
new file mode 100644
index 0000000..0ebb555
Binary files /dev/null and b/sample/src/main/res/drawable-xxhdpi/ic_done.png differ
diff --git a/sample/src/main/res/layout/recyclerview_activity.xml b/sample/src/main/res/layout/recyclerview_activity.xml
index 8407a59..878d84a 100644
--- a/sample/src/main/res/layout/recyclerview_activity.xml
+++ b/sample/src/main/res/layout/recyclerview_activity.xml
@@ -21,4 +21,25 @@
fab:fab_showAnimation="@anim/show_from_bottom"
fab:fab_hideAnimation="@anim/hide_to_bottom"/>
+
+
\ No newline at end of file