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 2973a44..a17a47d 100755
--- a/library/src/main/java/com/github/clans/fab/FloatingActionButton.java
+++ b/library/src/main/java/com/github/clans/fab/FloatingActionButton.java
@@ -32,15 +32,16 @@ public class FloatingActionButton extends ImageButton {
public static final int SIZE_NORMAL = 0;
public static final int SIZE_MINI = 1;
- private int mFabSize;
+ int mFabSize;
+ boolean mShowShadow;
+ int mShadowColor;
+ int mShadowRadius = Util.dpToPx(getContext(), 4f);
+ int mShadowXOffset = Util.dpToPx(getContext(), 1f);
+ int mShadowYOffset = Util.dpToPx(getContext(), 3f);
+
private int mColorNormal;
private int mColorPressed;
private int mColorRipple;
- private boolean mShowShadow;
- private int mShadowColor;
- private int mShadowRadius = Util.dpToPx(getContext(), 4f);
- private int mShadowXOffset = Util.dpToPx(getContext(), 1f);
- private int mShadowYOffset = Util.dpToPx(getContext(), 3f);
private Drawable mIcon;
private int mIconSize = Util.dpToPx(getContext(), 24f);
private Animation mShowAnimation;
@@ -254,7 +255,6 @@ void setColors(int colorNormal, int colorPressed, int colorRipple) {
mColorNormal = colorNormal;
mColorPressed = colorPressed;
mColorRipple = colorRipple;
- updateBackground();
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
diff --git a/library/src/main/java/com/github/clans/fab/FloatingActionMenu.java b/library/src/main/java/com/github/clans/fab/FloatingActionMenu.java
index e504edc..3d8fd86 100755
--- a/library/src/main/java/com/github/clans/fab/FloatingActionMenu.java
+++ b/library/src/main/java/com/github/clans/fab/FloatingActionMenu.java
@@ -4,10 +4,8 @@
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.TypedArray;
-import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
import android.os.Handler;
import android.text.TextUtils;
import android.util.AttributeSet;
@@ -19,6 +17,7 @@
import android.view.animation.AnticipateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.OvershootInterpolator;
+import android.widget.ImageView;
public class FloatingActionMenu extends ViewGroup {
@@ -26,8 +25,9 @@ public class FloatingActionMenu extends ViewGroup {
private static final float CLOSED_PLUS_ROTATION = 0f;
private static final float OPENED_PLUS_ROTATION = -90f - 45f;
- private AnimatorSet mOpenAnimatorSet = new AnimatorSet().setDuration(ANIMATION_DURATION);
- private AnimatorSet mCloseAnimatorSet = new AnimatorSet().setDuration(ANIMATION_DURATION);
+ private AnimatorSet mOpenAnimatorSet = new AnimatorSet();
+ private AnimatorSet mCloseAnimatorSet = new AnimatorSet();
+ private AnimatorSet mIconToggleSet;
private int mButtonSpacing = Util.dpToPx(getContext(), 0f);
private FloatingActionButton mMenuButton;
@@ -69,6 +69,7 @@ public class FloatingActionMenu extends ViewGroup {
private int mMenuFabSize;
private int mLabelsStyle;
private boolean mIconAnimated = true;
+ private ImageView mImageToggle;
private OnMenuToggleListener mToggleListener;
@@ -145,34 +146,19 @@ private void initPadding(int padding) {
}
private void createMenuButton() {
- mMenuButton = new FloatingActionButton(getContext()) {
+ mMenuButton = new FloatingActionButton(getContext());
- @Override
- protected Drawable getIconDrawable() {
- RotatingDrawable rotatingDrawable = new RotatingDrawable(mIcon);
-
- ObjectAnimator collapseAnimator = ObjectAnimator.ofFloat(rotatingDrawable, "rotation", OPENED_PLUS_ROTATION, CLOSED_PLUS_ROTATION);
- ObjectAnimator expandAnimator = ObjectAnimator.ofFloat(rotatingDrawable, "rotation", CLOSED_PLUS_ROTATION, OPENED_PLUS_ROTATION);
-
- mOpenAnimatorSet.play(expandAnimator);
- mCloseAnimatorSet.play(collapseAnimator);
-
- mOpenAnimatorSet.setInterpolator(mOpenInterpolator);
- mCloseAnimatorSet.setInterpolator(mCloseInterpolator);
-
- return rotatingDrawable;
- }
- };
-
- mMenuButton.setShowShadow(mMenuShowShadow);
+ mMenuButton.mShowShadow = mMenuShowShadow;
if (mMenuShowShadow) {
- mMenuButton.setShadowRadius(mMenuShadowRadius);
- mMenuButton.setShadowXOffset(mMenuShadowXOffset);
- mMenuButton.setShadowYOffset(mMenuShadowYOffset);
+ mMenuButton.mShadowRadius = Util.dpToPx(getContext(), mMenuShadowRadius);
+ mMenuButton.mShadowXOffset = Util.dpToPx(getContext(), mMenuShadowXOffset);
+ mMenuButton.mShadowYOffset = Util.dpToPx(getContext(), mMenuShadowYOffset);
}
mMenuButton.setColors(mMenuColorNormal, mMenuColorPressed, mMenuColorRipple);
- mMenuButton.setShadowColor(mMenuShadowColor);
- mMenuButton.setButtonSize(mMenuFabSize);
+ mMenuButton.mShadowColor = mMenuShadowColor;
+ mMenuButton.mFabSize = mMenuFabSize;
+ mMenuButton.updateBackground();
+
mMenuButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
@@ -180,7 +166,27 @@ public void onClick(View v) {
}
});
+ mImageToggle = new ImageView(getContext());
+ mImageToggle.setImageDrawable(mIcon);
+
addView(mMenuButton, super.generateDefaultLayoutParams());
+ addView(mImageToggle);
+
+ createDefaultIconAnimation();
+ }
+
+ private void createDefaultIconAnimation() {
+ ObjectAnimator collapseAnimator = ObjectAnimator.ofFloat(mImageToggle, "rotation", OPENED_PLUS_ROTATION, CLOSED_PLUS_ROTATION);
+ ObjectAnimator expandAnimator = ObjectAnimator.ofFloat(mImageToggle, "rotation", CLOSED_PLUS_ROTATION, OPENED_PLUS_ROTATION);
+
+ mOpenAnimatorSet.play(expandAnimator);
+ mCloseAnimatorSet.play(collapseAnimator);
+
+ mOpenAnimatorSet.setInterpolator(mOpenInterpolator);
+ mCloseAnimatorSet.setInterpolator(mCloseInterpolator);
+
+ mOpenAnimatorSet.setDuration(ANIMATION_DURATION);
+ mCloseAnimatorSet.setDuration(ANIMATION_DURATION);
}
@Override
@@ -190,10 +196,12 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
mMaxButtonWidth = 0;
int maxLabelWidth = 0;
+ measureChildWithMargins(mImageToggle, widthMeasureSpec, 0, heightMeasureSpec, 0);
+
for (int i = 0; i < mButtonsCount; i++) {
View child = getChildAt(i);
- if (child.getVisibility() == GONE) continue;
+ if (child.getVisibility() == GONE || child == mImageToggle) continue;
measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
mMaxButtonWidth = Math.max(mMaxButtonWidth, child.getMeasuredWidth());
@@ -203,7 +211,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int usedWidth = 0;
View child = getChildAt(i);
- if (child.getVisibility() == GONE) continue;
+ if (child.getVisibility() == GONE || child == mImageToggle) continue;
usedWidth += child.getMeasuredWidth();
height += child.getMeasuredHeight();
@@ -235,30 +243,39 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) {
mMenuButton.layout(menuButtonLeft, menuButtonTop, menuButtonLeft + mMenuButton.getMeasuredWidth(),
menuButtonTop + mMenuButton.getMeasuredHeight());
+ int imageLeft = buttonsHorizontalCenter - mImageToggle.getMeasuredWidth() / 2;
+ int imageTop = menuButtonTop + mMenuButton.getMeasuredHeight() / 2 - mImageToggle.getMeasuredHeight() / 2;
+
+ mImageToggle.layout(imageLeft, imageTop, imageLeft + mImageToggle.getMeasuredWidth(),
+ imageTop + mImageToggle.getMeasuredHeight());
+
int nextY = menuButtonTop - mButtonSpacing;
for (int i = mButtonsCount - 1; i >= 0; i--) {
- FloatingActionButton child = (FloatingActionButton) getChildAt(i);
+ View child = getChildAt(i);
- if (child == mMenuButton || child.getVisibility() == GONE) continue;
+ if (child == mImageToggle) continue;
- int childX = buttonsHorizontalCenter - child.getMeasuredWidth() / 2;
- int childY = nextY - child.getMeasuredHeight();
- child.layout(childX, childY, childX + child.getMeasuredWidth(),
- childY + child.getMeasuredHeight());
+ FloatingActionButton fab = (FloatingActionButton) child;
+ if (fab == mMenuButton || fab.getVisibility() == GONE) continue;
+
+ int childX = buttonsHorizontalCenter - fab.getMeasuredWidth() / 2;
+ int childY = nextY - fab.getMeasuredHeight();
+ fab.layout(childX, childY, childX + fab.getMeasuredWidth(),
+ childY + fab.getMeasuredHeight());
if (!mMenuOpened) {
- child.hide(false);
+ fab.hide(false);
}
- View label = (View) child.getTag(R.id.fab_label);
+ View label = (View) fab.getTag(R.id.fab_label);
if (label != null) {
- int labelsOffset = child.getMeasuredWidth() / 2 + mLabelsMargin;
+ int labelsOffset = fab.getMeasuredWidth() / 2 + mLabelsMargin;
int labelXNearButton = buttonsHorizontalCenter - labelsOffset;
int labelXAwayFromButton = labelXNearButton - label.getMeasuredWidth();
- int labelTop = childY - mLabelsVerticalOffset + (child.getMeasuredHeight()
+ int labelTop = childY - mLabelsVerticalOffset + (fab.getMeasuredHeight()
- label.getMeasuredHeight()) / 2;
label.layout(labelXAwayFromButton, labelTop,
@@ -279,6 +296,7 @@ private int adjustForOvershoot(int dimension) {
protected void onFinishInflate() {
super.onFinishInflate();
bringChildToFront(mMenuButton);
+ bringChildToFront(mImageToggle);
mButtonsCount = getChildCount();
createLabels();
}
@@ -287,6 +305,9 @@ private void createLabels() {
Context context = new ContextThemeWrapper(getContext(), mLabelsStyle);
for (int i = 0; i < mButtonsCount; i++) {
+
+ if (getChildAt(i) == mImageToggle) continue;
+
final FloatingActionButton fab = (FloatingActionButton) getChildAt(i);
String text = fab.getLabelText();
@@ -359,34 +380,6 @@ private void setLabelEllipsize(Label label) {
}
}
- private static class RotatingDrawable extends LayerDrawable {
-
- public RotatingDrawable(Drawable drawable) {
- super(new Drawable[]{drawable});
- }
-
- private float mRotation;
-
- @SuppressWarnings("UnusedDeclaration")
- public float getRotation() {
- return mRotation;
- }
-
- @SuppressWarnings("UnusedDeclaration")
- public void setRotation(float rotation) {
- mRotation = rotation;
- invalidateSelf();
- }
-
- @Override
- public void draw(Canvas canvas) {
- canvas.save();
- canvas.rotate(mRotation, getBounds().centerX(), getBounds().centerY());
- super.draw(canvas);
- canvas.restore();
- }
- }
-
@Override
public MarginLayoutParams generateLayoutParams(AttributeSet attrs) {
return new MarginLayoutParams(getContext(), attrs);
@@ -425,8 +418,12 @@ public void toggle(boolean animate) {
public void open(final boolean animate) {
if (!isOpened()) {
if (mIconAnimated) {
- mCloseAnimatorSet.cancel();
- mOpenAnimatorSet.start();
+ if (mIconToggleSet != null) {
+ mIconToggleSet.start();
+ } else {
+ mCloseAnimatorSet.cancel();
+ mOpenAnimatorSet.start();
+ }
}
mMenuOpened = true;
int delay = 0;
@@ -459,8 +456,12 @@ public void run() {
public void close(final boolean animate) {
if (isOpened()) {
if (mIconAnimated) {
- mCloseAnimatorSet.start();
- mOpenAnimatorSet.cancel();
+ if (mIconToggleSet != null) {
+ mIconToggleSet.start();
+ } else {
+ mCloseAnimatorSet.start();
+ mOpenAnimatorSet.cancel();
+ }
}
mMenuOpened = false;
int delay = 0;
@@ -542,4 +543,16 @@ public void setIconAnimated(boolean animated) {
public boolean isIconAnimated() {
return mIconAnimated;
}
+
+ public ImageView getMenuIconView() {
+ return mImageToggle;
+ }
+
+ public void setIconToggleAnimatorSet(AnimatorSet toggleAnimatorSet) {
+ mIconToggleSet = toggleAnimatorSet;
+ }
+
+ public AnimatorSet getIconToggleAnimatorSet() {
+ return mIconToggleSet;
+ }
}
diff --git a/library/src/main/java/com/github/clans/fab/Util.java b/library/src/main/java/com/github/clans/fab/Util.java
index 5e9ad4f..909f4fb 100755
--- a/library/src/main/java/com/github/clans/fab/Util.java
+++ b/library/src/main/java/com/github/clans/fab/Util.java
@@ -3,7 +3,7 @@
import android.content.Context;
import android.os.Build;
-public final class Util {
+final class Util {
private Util() {
}
diff --git a/sample/proguard-rules.pro b/sample/proguard-rules.pro
index bb0d74f..80fd597 100755
--- a/sample/proguard-rules.pro
+++ b/sample/proguard-rules.pro
@@ -14,10 +14,4 @@
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
-#}
-
-# keep getters/setters in RotatingDrawable so that animations can still work.
--keepclassmembers class com.github.clans.fab.FloatingActionMenu$RotatingDrawable {
- void set*(***);
- *** get*();
-}
\ No newline at end of file
+#}
\ No newline at end of file
diff --git a/sample/src/main/java/com/github/clans/fab/sample/FloatingMenusActivity.java b/sample/src/main/java/com/github/clans/fab/sample/FloatingMenusActivity.java
index 4dbee74..a175264 100755
--- a/sample/src/main/java/com/github/clans/fab/sample/FloatingMenusActivity.java
+++ b/sample/src/main/java/com/github/clans/fab/sample/FloatingMenusActivity.java
@@ -1,5 +1,9 @@
package com.github.clans.fab.sample;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
@@ -81,6 +85,40 @@ public void onClick(View v) {
startActivity(new Intent(FloatingMenusActivity.this, RecyclerViewActivity.class));
}
});
+
+ createCustomAnimation();
+ }
+
+ private void createCustomAnimation() {
+ final FloatingActionMenu menu4 = (FloatingActionMenu) findViewById(R.id.menu4);
+
+ AnimatorSet set = new AnimatorSet();
+
+ ObjectAnimator scaleOutX = ObjectAnimator.ofFloat(menu4.getMenuIconView(), "scaleX", 1.0f, 0.2f);
+ ObjectAnimator scaleOutY = ObjectAnimator.ofFloat(menu4.getMenuIconView(), "scaleY", 1.0f, 0.2f);
+
+ ObjectAnimator scaleInX = ObjectAnimator.ofFloat(menu4.getMenuIconView(), "scaleX", 0.2f, 1.0f);
+ ObjectAnimator scaleInY = ObjectAnimator.ofFloat(menu4.getMenuIconView(), "scaleY", 0.2f, 1.0f);
+
+ scaleOutX.setDuration(50);
+ scaleOutY.setDuration(50);
+
+ scaleInX.setDuration(150);
+ scaleInY.setDuration(150);
+
+ scaleInX.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ menu4.getMenuIconView().setImageResource(menu4.isOpened()
+ ? R.drawable.ic_close : R.drawable.ic_star);
+ }
+ });
+
+ set.play(scaleOutX).with(scaleOutY);
+ set.play(scaleInX).with(scaleInY).after(scaleOutX);
+ set.setInterpolator(new OvershootInterpolator(2));
+
+ menu4.setIconToggleAnimatorSet(set);
}
@Override
diff --git a/sample/src/main/res/drawable-hdpi/ic_close.png b/sample/src/main/res/drawable-hdpi/ic_close.png
new file mode 100755
index 0000000..d664996
Binary files /dev/null and b/sample/src/main/res/drawable-hdpi/ic_close.png differ
diff --git a/sample/src/main/res/drawable-mdpi/ic_close.png b/sample/src/main/res/drawable-mdpi/ic_close.png
new file mode 100755
index 0000000..f3d2658
Binary files /dev/null and b/sample/src/main/res/drawable-mdpi/ic_close.png differ
diff --git a/sample/src/main/res/drawable-xhdpi/ic_close.png b/sample/src/main/res/drawable-xhdpi/ic_close.png
new file mode 100755
index 0000000..a7046c5
Binary files /dev/null and b/sample/src/main/res/drawable-xhdpi/ic_close.png differ
diff --git a/sample/src/main/res/drawable-xxhdpi/ic_close.png b/sample/src/main/res/drawable-xxhdpi/ic_close.png
new file mode 100755
index 0000000..a712745
Binary files /dev/null and b/sample/src/main/res/drawable-xxhdpi/ic_close.png differ
diff --git a/sample/src/main/res/layout/floating_menus_activity.xml b/sample/src/main/res/layout/floating_menus_activity.xml
index 45a8668..4d763ab 100755
--- a/sample/src/main/res/layout/floating_menus_activity.xml
+++ b/sample/src/main/res/layout/floating_menus_activity.xml
@@ -64,7 +64,7 @@
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
- android:layout_marginRight="90dp"
+ android:layout_marginRight="80dp"
android:layout_marginBottom="10dp"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
@@ -103,13 +103,54 @@
+
+
+
+
+
+
+
+
+
+
#62B2FF
+
+