package com.github.clans.fab;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.ContextThemeWrapper;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.AnticipateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.OvershootInterpolator;
import android.widget.ImageView;
import android.widget.Toast;
public class FloatingActionMenu extends ViewGroup {
private static final int ANIMATION_DURATION = 300;
private static final float CLOSED_PLUS_ROTATION = 0f;
private static final float OPENED_PLUS_ROTATION_LEFT = -90f - 45f;
private static final float OPENED_PLUS_ROTATION_RIGHT = 90f + 45f;
private static final int OPEN_UP = 0;
private static final int OPEN_DOWN = 1;
private static final int LABELS_POSITION_LEFT = 0;
private static final int LABELS_POSITION_RIGHT = 1;
private AnimatorSet mOpenAnimatorSet = new AnimatorSet();
private AnimatorSet mCloseAnimatorSet = new AnimatorSet();
private AnimatorSet mIconToggleSet;
private int mButtonSpacing = Util.dpToPx(getContext(), 0f);
private FloatingActionButton mMenuButton;
private int mMaxButtonWidth;
private int mLabelsMargin = Util.dpToPx(getContext(), 0f);
private int mLabelsVerticalOffset = Util.dpToPx(getContext(), 0f);
private int mButtonsCount;
private boolean mMenuOpened;
private boolean mIsMenuOpening;
private Handler mUiHandler = new Handler();
private int mLabelsShowAnimation;
private int mLabelsHideAnimation;
private int mLabelsPaddingTop = Util.dpToPx(getContext(), 4f);
private int mLabelsPaddingRight = Util.dpToPx(getContext(), 8f);
private int mLabelsPaddingBottom = Util.dpToPx(getContext(), 4f);
private int mLabelsPaddingLeft = Util.dpToPx(getContext(), 8f);
private int mLabelsTextColor;
private float mLabelsTextSize;
private int mLabelsCornerRadius = Util.dpToPx(getContext(), 3f);
private boolean mLabelsShowShadow;
private int mLabelsColorNormal;
private int mLabelsColorPressed;
private int mLabelsColorRipple;
private boolean mMenuShowShadow;
private int mMenuShadowColor;
private float mMenuShadowRadius = 4f;
private float mMenuShadowXOffset = 1f;
private float mMenuShadowYOffset = 3f;
private int mMenuColorNormal;
private int mMenuColorPressed;
private int mMenuColorRipple;
private Drawable mIcon;
private int mAnimationDelayPerItem;
private Interpolator mOpenInterpolator;
private Interpolator mCloseInterpolator;
private boolean mIsAnimated = true;
private boolean mLabelsSingleLine;
private int mLabelsEllipsize;
private int mLabelsMaxLines;
private int mMenuFabSize;
private int mLabelsStyle;
private boolean mIconAnimated = true;
private ImageView mImageToggle;
private Animation mMenuButtonShowAnimation;
private Animation mMenuButtonHideAnimation;
private boolean mIsMenuButtonAnimationRunning;
private boolean mIsSetClosedOnTouchOutside;
private int mOpenDirection;
private OnMenuToggleListener mToggleListener;
private ValueAnimator mShowBackgroundAnimator;
private ValueAnimator mHideBackgroundAnimator;
private int mBackgroundColor;
private int mLabelsPosition;
private Context mLabelsContext;
public interface OnMenuToggleListener {
void onMenuToggle(boolean opened);
}
public FloatingActionMenu(Context context) {
this(context, null);
}
public FloatingActionMenu(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FloatingActionMenu(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
TypedArray attr = context.obtainStyledAttributes(attrs, R.styleable.FloatingActionMenu, 0, 0);
mButtonSpacing = attr.getDimensionPixelSize(R.styleable.FloatingActionMenu_menu_buttonSpacing, mButtonSpacing);
mLabelsMargin = attr.getDimensionPixelSize(R.styleable.FloatingActionMenu_menu_labels_margin, mLabelsMargin);
mLabelsPosition = attr.getInt(R.styleable.FloatingActionMenu_menu_labels_position, LABELS_POSITION_LEFT);
mLabelsShowAnimation = attr.getResourceId(R.styleable.FloatingActionMenu_menu_labels_showAnimation,
mLabelsPosition == LABELS_POSITION_LEFT ? R.anim.fab_slide_in_from_right : R.anim.fab_slide_in_from_left);
mLabelsHideAnimation = attr.getResourceId(R.styleable.FloatingActionMenu_menu_labels_hideAnimation,
mLabelsPosition == LABELS_POSITION_LEFT ? R.anim.fab_slide_out_to_right : R.anim.fab_slide_out_to_left);
mLabelsPaddingTop = attr.getDimensionPixelSize(R.styleable.FloatingActionMenu_menu_labels_paddingTop, mLabelsPaddingTop);
mLabelsPaddingRight = attr.getDimensionPixelSize(R.styleable.FloatingActionMenu_menu_labels_paddingRight, mLabelsPaddingRight);
mLabelsPaddingBottom = attr.getDimensionPixelSize(R.styleable.FloatingActionMenu_menu_labels_paddingBottom, mLabelsPaddingBottom);
mLabelsPaddingLeft = attr.getDimensionPixelSize(R.styleable.FloatingActionMenu_menu_labels_paddingLeft, mLabelsPaddingLeft);
mLabelsTextColor = attr.getColor(R.styleable.FloatingActionMenu_menu_labels_textColor, Color.WHITE);
mLabelsTextSize = attr.getDimension(R.styleable.FloatingActionMenu_menu_labels_textSize, getResources().getDimension(R.dimen.labels_text_size));
mLabelsCornerRadius = attr.getDimensionPixelSize(R.styleable.FloatingActionMenu_menu_labels_cornerRadius, mLabelsCornerRadius);
mLabelsShowShadow = attr.getBoolean(R.styleable.FloatingActionMenu_menu_labels_showShadow, true);
mLabelsColorNormal = attr.getColor(R.styleable.FloatingActionMenu_menu_labels_colorNormal, 0xFF333333);
mLabelsColorPressed = attr.getColor(R.styleable.FloatingActionMenu_menu_labels_colorPressed, 0xFF444444);
mLabelsColorRipple = attr.getColor(R.styleable.FloatingActionMenu_menu_labels_colorRipple, 0x66FFFFFF);
mMenuShowShadow = attr.getBoolean(R.styleable.FloatingActionMenu_menu_showShadow, true);
mMenuShadowColor = attr.getColor(R.styleable.FloatingActionMenu_menu_shadowColor, 0x66000000);
mMenuShadowRadius = attr.getDimension(R.styleable.FloatingActionMenu_menu_shadowRadius, mMenuShadowRadius);
mMenuShadowXOffset = attr.getDimension(R.styleable.FloatingActionMenu_menu_shadowXOffset, mMenuShadowXOffset);
mMenuShadowYOffset = attr.getDimension(R.styleable.FloatingActionMenu_menu_shadowYOffset, mMenuShadowYOffset);
mMenuColorNormal = attr.getColor(R.styleable.FloatingActionMenu_menu_colorNormal, 0xFFDA4336);
mMenuColorPressed = attr.getColor(R.styleable.FloatingActionMenu_menu_colorPressed, 0xFFE75043);
mMenuColorRipple = attr.getColor(R.styleable.FloatingActionMenu_menu_colorRipple, 0x99FFFFFF);
mAnimationDelayPerItem = attr.getInt(R.styleable.FloatingActionMenu_menu_animationDelayPerItem, 50);
mIcon = attr.getDrawable(R.styleable.FloatingActionMenu_menu_icon);
if (mIcon == null) {
mIcon = getResources().getDrawable(R.drawable.fab_add);
}
mLabelsSingleLine = attr.getBoolean(R.styleable.FloatingActionMenu_menu_labels_singleLine, false);
mLabelsEllipsize = attr.getInt(R.styleable.FloatingActionMenu_menu_labels_ellipsize, 0);
mLabelsMaxLines = attr.getInt(R.styleable.FloatingActionMenu_menu_labels_maxLines, -1);
mMenuFabSize = attr.getInt(R.styleable.FloatingActionMenu_menu_fab_size, FloatingActionButton.SIZE_NORMAL);
mLabelsStyle = attr.getResourceId(R.styleable.FloatingActionMenu_menu_labels_style, 0);
mOpenDirection = attr.getInt(R.styleable.FloatingActionMenu_menu_openDirection, OPEN_UP);
mBackgroundColor = attr.getColor(R.styleable.FloatingActionMenu_menu_backgroundColor, Color.TRANSPARENT);
if (attr.hasValue(R.styleable.FloatingActionMenu_menu_labels_padding)) {
int padding = attr.getDimensionPixelSize(R.styleable.FloatingActionMenu_menu_labels_padding, 0);
initPadding(padding);
}
attr.recycle();
mOpenInterpolator = new OvershootInterpolator();
mCloseInterpolator = new AnticipateInterpolator();
mLabelsContext = new ContextThemeWrapper(getContext(), mLabelsStyle);
initMenuButtonAnimations();
initBackgroundDimAnimation();
createMenuButton();
}
private void initMenuButtonAnimations() {
mMenuButtonShowAnimation = AnimationUtils.loadAnimation(getContext(), R.anim.fab_scale_up);
mMenuButtonHideAnimation = AnimationUtils.loadAnimation(getContext(), R.anim.fab_scale_down);
}
private void initBackgroundDimAnimation() {
final int maxAlpha = Color.alpha(mBackgroundColor);
final int red = Color.red(mBackgroundColor);
final int green = Color.green(mBackgroundColor);
final int blue = Color.blue(mBackgroundColor);
mShowBackgroundAnimator = ValueAnimator.ofInt(0, maxAlpha);
mShowBackgroundAnimator.setDuration(ANIMATION_DURATION);
mShowBackgroundAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Integer alpha = (Integer) animation.getAnimatedValue();
setBackgroundColor(Color.argb(alpha, red, green, blue));
}
});
mHideBackgroundAnimator = ValueAnimator.ofInt(maxAlpha, 0);
mHideBackgroundAnimator.setDuration(ANIMATION_DURATION);
mHideBackgroundAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Integer alpha = (Integer) animation.getAnimatedValue();
setBackgroundColor(Color.argb(alpha, red, green, blue));
}
});
}
private boolean isBackgroundEnabled() {
return mBackgroundColor != Color.TRANSPARENT;
}
private void initPadding(int padding) {
mLabelsPaddingTop = padding;
mLabelsPaddingRight = padding;
mLabelsPaddingBottom = padding;
mLabelsPaddingLeft = padding;
}
private void createMenuButton() {
mMenuButton = new FloatingActionButton(getContext());
mMenuButton.mShowShadow = mMenuShowShadow;
if (mMenuShowShadow) {
mMenuButton.mShadowRadius = Util.dpToPx(getContext(), mMenuShadowRadius);
mMenuButton.mShadowXOffset = Util.dpToPx(getContext(), mMenuShadowXOffset);
mMenuButton.mShadowYOffset = Util.dpToPx(getContext(), mMenuShadowYOffset);
}
mMenuButton.setColors(mMenuColorNormal, mMenuColorPressed, mMenuColorRipple);
mMenuButton.mShadowColor = mMenuShadowColor;
mMenuButton.mFabSize = mMenuFabSize;
mMenuButton.updateBackground();
mMenuButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
toggle(mIsAnimated);
}
});
mImageToggle = new ImageView(getContext());
mImageToggle.setImageDrawable(mIcon);
addView(mMenuButton, super.generateDefaultLayoutParams());
addView(mImageToggle);
createDefaultIconAnimation();
}
private void createDefaultIconAnimation() {
float collapseAngle;
float expandAngle;
if (mOpenDirection == OPEN_UP) {
collapseAngle = mLabelsPosition == LABELS_POSITION_LEFT ? OPENED_PLUS_ROTATION_LEFT : OPENED_PLUS_ROTATION_RIGHT;
expandAngle = mLabelsPosition == LABELS_POSITION_LEFT ? OPENED_PLUS_ROTATION_LEFT : OPENED_PLUS_ROTATION_RIGHT;
} else {
collapseAngle = mLabelsPosition == LABELS_POSITION_LEFT ? OPENED_PLUS_ROTATION_RIGHT : OPENED_PLUS_ROTATION_LEFT;
expandAngle = mLabelsPosition == LABELS_POSITION_LEFT ? OPENED_PLUS_ROTATION_RIGHT : OPENED_PLUS_ROTATION_LEFT;
}
ObjectAnimator collapseAnimator = ObjectAnimator.ofFloat(
mImageToggle,
"rotation",
collapseAngle,
CLOSED_PLUS_ROTATION
);
ObjectAnimator expandAnimator = ObjectAnimator.ofFloat(
mImageToggle,
"rotation",
CLOSED_PLUS_ROTATION,
expandAngle
);
mOpenAnimatorSet.play(expandAnimator);
mCloseAnimatorSet.play(collapseAnimator);
mOpenAnimatorSet.setInterpolator(mOpenInterpolator);
mCloseAnimatorSet.setInterpolator(mCloseInterpolator);
mOpenAnimatorSet.setDuration(ANIMATION_DURATION);
mCloseAnimatorSet.setDuration(ANIMATION_DURATION);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = 0;
int height = 0;
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 || child == mImageToggle) continue;
measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
mMaxButtonWidth = Math.max(mMaxButtonWidth, child.getMeasuredWidth());
}
for (int i = 0; i < mButtonsCount; i++) {
int usedWidth = 0;
View child = getChildAt(i);
if (child.getVisibility() == GONE || child == mImageToggle) continue;
usedWidth += child.getMeasuredWidth();
height += child.getMeasuredHeight();
Label label = (Label) child.getTag(R.id.fab_label);
if (label != null) {
int labelOffset = (mMaxButtonWidth - child.getMeasuredWidth()) / 2;
int labelUsedWidth = child.getMeasuredWidth() + label.calculateShadowWidth() + mLabelsMargin + labelOffset;
measureChildWithMargins(label, widthMeasureSpec, labelUsedWidth, heightMeasureSpec, 0);
usedWidth += label.getMeasuredWidth();
maxLabelWidth = Math.max(maxLabelWidth, usedWidth + labelOffset);
}
}
width = Math.max(mMaxButtonWidth, maxLabelWidth + mLabelsMargin) + getPaddingLeft() + getPaddingRight();
height += mButtonSpacing * (mButtonsCount - 1) + getPaddingTop() + getPaddingBottom();
height = adjustForOvershoot(height);
if (getLayoutParams().width == LayoutParams.MATCH_PARENT) {
width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
}
if (getLayoutParams().height == LayoutParams.MATCH_PARENT) {
height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
}
setMeasuredDimension(width, height);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int buttonsHorizontalCenter = mLabelsPosition == LABELS_POSITION_LEFT
? r - l - mMaxButtonWidth / 2 - getPaddingRight()
: mMaxButtonWidth / 2 + getPaddingLeft();
boolean openUp = mOpenDirection == OPEN_UP;
int menuButtonTop = openUp
? b - t - mMenuButton.getMeasuredHeight() - getPaddingBottom()
: getPaddingTop();
int menuButtonLeft = buttonsHorizontalCenter - mMenuButton.getMeasuredWidth() / 2;
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 = openUp
? menuButtonTop - mButtonSpacing
: menuButtonTop + mMenuButton.getMeasuredHeight() + mButtonSpacing;
for (int i = mButtonsCount - 1; i >= 0; i--) {
View child = getChildAt(i);
if (child == mImageToggle) continue;
FloatingActionButton fab = (FloatingActionButton) child;
if (fab == mMenuButton || fab.getVisibility() == GONE) continue;
int childX = buttonsHorizontalCenter - fab.getMeasuredWidth() / 2;
int childY = openUp ? nextY - fab.getMeasuredHeight() : nextY;
fab.layout(childX, childY, childX + fab.getMeasuredWidth(),
childY + fab.getMeasuredHeight());
if (!mIsMenuOpening) {
fab.hide(false);
}
View label = (View) fab.getTag(R.id.fab_label);
if (label != null) {
int labelsOffset = fab.getMeasuredWidth() / 2 + mLabelsMargin;
int labelXNearButton = mLabelsPosition == LABELS_POSITION_LEFT
? buttonsHorizontalCenter - labelsOffset
: buttonsHorizontalCenter + labelsOffset;
int labelXAwayFromButton = mLabelsPosition == LABELS_POSITION_LEFT
? labelXNearButton - label.getMeasuredWidth()
: labelXNearButton + label.getMeasuredWidth();
int labelLeft = mLabelsPosition == LABELS_POSITION_LEFT
? labelXAwayFromButton
: labelXNearButton;
int labelRight = mLabelsPosition == LABELS_POSITION_LEFT
? labelXNearButton
: labelXAwayFromButton;
int labelTop = childY - mLabelsVerticalOffset + (fab.getMeasuredHeight()
- label.getMeasuredHeight()) / 2;
label.layout(labelLeft, labelTop, labelRight, labelTop + label.getMeasuredHeight());
if (!mIsMenuOpening) {
label.setVisibility(INVISIBLE);
}
}
nextY = openUp
? childY - mButtonSpacing
: childY + child.getMeasuredHeight() + mButtonSpacing;
}
}
private int adjustForOvershoot(int dimension) {
return (int) (dimension * 0.03 + dimension);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
bringChildToFront(mMenuButton);
bringChildToFront(mImageToggle);
mButtonsCount = getChildCount();
createLabels();
}
private void createLabels() {
for (int i = 0; i < mButtonsCount; i++) {
if (getChildAt(i) == mImageToggle) continue;
final FloatingActionButton fab = (FloatingActionButton) getChildAt(i);
if (fab == mMenuButton || fab.getTag(R.id.fab_label) != null) continue;
addLabel(fab);
}
}
private void addLabel(FloatingActionButton fab) {
String text = fab.getLabelText();
if (TextUtils.isEmpty(text)) return;
final Label label = new Label(mLabelsContext);
label.setFab(fab);
label.setShowAnimation(AnimationUtils.loadAnimation(getContext(), mLabelsShowAnimation));
label.setHideAnimation(AnimationUtils.loadAnimation(getContext(), mLabelsHideAnimation));
if (mLabelsStyle > 0) {
label.setTextAppearance(getContext(), mLabelsStyle);
label.setShowShadow(false);
label.setUsingStyle(true);
} else {
label.setColors(mLabelsColorNormal, mLabelsColorPressed, mLabelsColorRipple);
label.setShowShadow(mLabelsShowShadow);
label.setCornerRadius(mLabelsCornerRadius);
if (mLabelsEllipsize > 0) {
setLabelEllipsize(label);
}
label.setMaxLines(mLabelsMaxLines);
label.updateBackground();
label.setTextSize(TypedValue.COMPLEX_UNIT_PX, mLabelsTextSize);
label.setTextColor(mLabelsTextColor);
int left = mLabelsPaddingLeft;
int top = mLabelsPaddingTop;
if (mLabelsShowShadow) {
left += fab.getShadowRadius() + Math.abs(fab.getShadowXOffset());
top += fab.getShadowRadius() + Math.abs(fab.getShadowYOffset());
}
label.setPadding(
left,
top,
mLabelsPaddingLeft,
mLabelsPaddingTop
);
if (mLabelsMaxLines < 0 || mLabelsSingleLine) {
label.setSingleLine(mLabelsSingleLine);
}
}
label.setText(text);
addView(label);
fab.setTag(R.id.fab_label, label);
}
private void setLabelEllipsize(Label label) {
switch (mLabelsEllipsize) {
case 1:
label.setEllipsize(TextUtils.TruncateAt.START);
break;
case 2:
label.setEllipsize(TextUtils.TruncateAt.MIDDLE);
break;
case 3:
label.setEllipsize(TextUtils.TruncateAt.END);
break;
case 4:
label.setEllipsize(TextUtils.TruncateAt.MARQUEE);
break;
}
}
@Override
public MarginLayoutParams generateLayoutParams(AttributeSet attrs) {
return new MarginLayoutParams(getContext(), attrs);
}
@Override
protected MarginLayoutParams generateLayoutParams(LayoutParams p) {
return new MarginLayoutParams(p);
}
@Override
protected MarginLayoutParams generateDefaultLayoutParams() {
return new MarginLayoutParams(MarginLayoutParams.WRAP_CONTENT,
MarginLayoutParams.WRAP_CONTENT);
}
@Override
protected boolean checkLayoutParams(LayoutParams p) {
return p instanceof MarginLayoutParams;
}
private void hideMenuButtonWithImage(boolean animate) {
if (!isMenuButtonHidden()) {
mMenuButton.hide(animate);
if (animate) {
mImageToggle.startAnimation(mMenuButtonHideAnimation);
}
mImageToggle.setVisibility(INVISIBLE);
mIsMenuButtonAnimationRunning = false;
}
}
private void showMenuButtonWithImage(boolean animate) {
if (isMenuButtonHidden()) {
mMenuButton.show(animate);
if (animate) {
mImageToggle.startAnimation(mMenuButtonShowAnimation);
}
mImageToggle.setVisibility(VISIBLE);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mIsSetClosedOnTouchOutside) {
return mGestureDetector.onTouchEvent(event);
} else {
return super.onTouchEvent(event);
}
}
GestureDetector mGestureDetector = new GestureDetector(getContext(),
new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onDown(MotionEvent e) {
return mIsSetClosedOnTouchOutside && isOpened();
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
close(mIsAnimated);
return true;
}
});
/* ===== API methods ===== */
public boolean isOpened() {
return mMenuOpened;
}
public void toggle(boolean animate) {
if (isOpened()) {
close(animate);
} else {
open(animate);
}
}
public void open(final boolean animate) {
if (!isOpened()) {
if (isBackgroundEnabled()) {
mShowBackgroundAnimator.start();
}
if (mIconAnimated) {
if (mIconToggleSet != null) {
mIconToggleSet.start();
} else {
mCloseAnimatorSet.cancel();
mOpenAnimatorSet.start();
}
}
int delay = 0;
int counter = 0;
mIsMenuOpening = true;
for (int i = getChildCount() - 1; i >= 0; i--) {
View child = getChildAt(i);
if (child instanceof FloatingActionButton
&& child != mMenuButton && child.getVisibility() != GONE) {
counter++;
final FloatingActionButton fab = (FloatingActionButton) child;
mUiHandler.postDelayed(new Runnable() {
@Override
public void run() {
if (isOpened()) return;
fab.show(animate);
Label label = (Label) fab.getTag(R.id.fab_label);
if (label != null && label.isHandleVisibilityChanges()) {
label.show(animate);
}
}
}, delay);
delay += mAnimationDelayPerItem;
}
}
mUiHandler.postDelayed(new Runnable() {
@Override
public void run() {
mMenuOpened = true;
if (mToggleListener != null) {
mToggleListener.onMenuToggle(true);
}
}
}, ++counter * mAnimationDelayPerItem);
}
}
public void close(final boolean animate) {
if (isOpened()) {
if (isBackgroundEnabled()) {
mHideBackgroundAnimator.start();
}
if (mIconAnimated) {
if (mIconToggleSet != null) {
mIconToggleSet.start();
} else {
mCloseAnimatorSet.start();
mOpenAnimatorSet.cancel();
}
}
int delay = 0;
int counter = 0;
mIsMenuOpening = false;
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (child instanceof FloatingActionButton
&& child != mMenuButton && child.getVisibility() != GONE) {
counter++;
final FloatingActionButton fab = (FloatingActionButton) child;
mUiHandler.postDelayed(new Runnable() {
@Override
public void run() {
if (!isOpened()) return;
fab.hide(animate);
Label label = (Label) fab.getTag(R.id.fab_label);
if (label != null && label.isHandleVisibilityChanges()) {
label.hide(animate);
}
}
}, delay);
delay += mAnimationDelayPerItem;
}
}
mUiHandler.postDelayed(new Runnable() {
@Override
public void run() {
mMenuOpened = false;
if (mToggleListener != null) {
mToggleListener.onMenuToggle(false);
}
}
}, ++counter * mAnimationDelayPerItem);
}
}
/**
* Sets the {@link android.view.animation.Interpolator} for <b>FloatingActionButton's</b> icon animation.
*
* @param interpolator the Interpolator to be used in animation
*/
public void setIconAnimationInterpolator(Interpolator interpolator) {
mOpenAnimatorSet.setInterpolator(interpolator);
mCloseAnimatorSet.setInterpolator(interpolator);
}
public void setIconAnimationOpenInterpolator(Interpolator openInterpolator) {
mOpenAnimatorSet.setInterpolator(openInterpolator);
}
public void setIconAnimationCloseInterpolator(Interpolator closeInterpolator) {
mCloseAnimatorSet.setInterpolator(closeInterpolator);
}
/**
* Sets whether open and close actions should be animated
*
* @param animated if <b>false</b> - menu items will appear/disappear instantly without any animation
*/
public void setAnimated(boolean animated) {
mIsAnimated = animated;
mOpenAnimatorSet.setDuration(animated ? ANIMATION_DURATION : 0);
mCloseAnimatorSet.setDuration(animated ? ANIMATION_DURATION : 0);
}
public boolean isAnimated() {
return mIsAnimated;
}
public void setAnimationDelayPerItem(int animationDelayPerItem) {
mAnimationDelayPerItem = animationDelayPerItem;
}
public int getAnimationDelayPerItem() {
return mAnimationDelayPerItem;
}
public void setOnMenuToggleListener(OnMenuToggleListener listener) {
mToggleListener = listener;
}
public void setIconAnimated(boolean animated) {
mIconAnimated = animated;
}
public boolean isIconAnimated() {
return mIconAnimated;
}
public ImageView getMenuIconView() {
return mImageToggle;
}
public void setIconToggleAnimatorSet(AnimatorSet toggleAnimatorSet) {
mIconToggleSet = toggleAnimatorSet;
}
public AnimatorSet getIconToggleAnimatorSet() {
return mIconToggleSet;
}
public void setMenuButtonShowAnimation(Animation showAnimation) {
mMenuButtonShowAnimation = showAnimation;
mMenuButton.setShowAnimation(showAnimation);
}
public void setMenuButtonHideAnimation(Animation hideAnimation) {
mMenuButtonHideAnimation = hideAnimation;
mMenuButton.setHideAnimation(hideAnimation);
}
public boolean isMenuButtonHidden() {
return mMenuButton.isHidden();
}
public void showMenuButton(boolean animate) {
if (isMenuButtonHidden()) {
showMenuButtonWithImage(animate);
}
}
public void hideMenuButton(final boolean animate) {
if (!isMenuButtonHidden() && !mIsMenuButtonAnimationRunning) {
mIsMenuButtonAnimationRunning = true;
if (isOpened()) {
close(animate);
mUiHandler.postDelayed(new Runnable() {
@Override
public void run() {
hideMenuButtonWithImage(animate);
}
}, mAnimationDelayPerItem * mButtonsCount);
} else {
hideMenuButtonWithImage(animate);
}
}
}
public void toggleMenuButton(boolean animate) {
if (isMenuButtonHidden()) {
showMenuButton(animate);
} else {
hideMenuButton(animate);
}
}
public void setClosedOnTouchOutside(boolean close) {
mIsSetClosedOnTouchOutside = close;
}
public void setMenuButtonColorNormal(int color) {
mMenuColorNormal = color;
mMenuButton.setColorNormal(color);
}
public void setMenuButtonColorNormalResId(int colorResId) {
mMenuColorNormal = getResources().getColor(colorResId);
mMenuButton.setColorNormalResId(colorResId);
}
public int getMenuButtonColorNormal() {
return mMenuColorNormal;
}
public void setMenuButtonColorPressed(int color) {
mMenuColorPressed = color;
mMenuButton.setColorPressed(color);
}
public void setMenuButtonColorPressedResId(int colorResId) {
mMenuColorPressed = getResources().getColor(colorResId);
mMenuButton.setColorPressedResId(colorResId);
}
public int getMenuButtonColorPressed() {
return mMenuColorPressed;
}
public void setMenuButtonColorRipple(int color) {
mMenuColorRipple = color;
mMenuButton.setColorRipple(color);
}
public void setMenuButtonColorRippleResId(int colorResId) {
mMenuColorRipple = getResources().getColor(colorResId);
mMenuButton.setColorRippleResId(colorResId);
}
public int getMenuButtonColorRipple() {
return mMenuColorRipple;
}
public void addMenuButton(FloatingActionButton fab) {
addView(fab, mButtonsCount - 2);
mButtonsCount++;
addLabel(fab);
}
public void removeMenuButton(FloatingActionButton fab) {
removeView(fab.getLabelView());
removeView(fab);
mButtonsCount--;
}
}