Created
December 16, 2014 07:39
-
-
Save sahinraj/67eb0e61ebdaaaad39e0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.getbase.floatingactionbutton; | |
import android.content.Context; | |
import android.content.res.TypedArray; | |
import android.graphics.Canvas; | |
import android.graphics.drawable.Drawable; | |
import android.graphics.drawable.LayerDrawable; | |
import android.os.Parcel; | |
import android.os.Parcelable; | |
import android.support.annotation.ColorRes; | |
import android.support.annotation.NonNull; | |
import android.util.AttributeSet; | |
import android.view.ContextThemeWrapper; | |
import android.view.View; | |
import android.view.ViewGroup; | |
import android.view.animation.DecelerateInterpolator; | |
import android.view.animation.Interpolator; | |
import android.view.animation.OvershootInterpolator; | |
import android.widget.TextView; | |
import com.nineoldandroids.animation.AnimatorSet; | |
import com.nineoldandroids.animation.ObjectAnimator; | |
import com.nineoldandroids.animation.PropertyValuesHolder; | |
import com.nineoldandroids.view.ViewHelper; | |
import com.whatsonindia.R; | |
import com.whatsonindia.adapterlist.CategoryAdapter.ViewHolder; | |
public class FloatingActionsMenu extends ViewGroup { | |
public static final int EXPAND_UP = 0; | |
public static final int EXPAND_DOWN = 1; | |
public static final int EXPAND_LEFT = 2; | |
public static final int EXPAND_RIGHT = 3; | |
private static final int ANIMATION_DURATION = 300; | |
private static final float COLLAPSED_PLUS_ROTATION = 0f; | |
private static final float EXPANDED_PLUS_ROTATION = 90f + 45f; | |
private int mAddButtonPlusColor; | |
private int mAddButtonColorNormal; | |
private int mAddButtonColorPressed; | |
private int mExpandDirection; | |
private int mButtonSpacing; | |
private int mLabelsMargin; | |
private int mLabelsVerticalOffset; | |
private boolean mExpanded; | |
private AnimatorSet mExpandAnimation = new AnimatorSet() | |
.setDuration(ANIMATION_DURATION); | |
private AnimatorSet mCollapseAnimation = new AnimatorSet() | |
.setDuration(ANIMATION_DURATION); | |
private AddFloatingActionButton mAddButton; | |
private RotatingDrawable mRotatingDrawable; | |
private int mLabelsStyle; | |
private int mButtonsCount; | |
public FloatingActionsMenu(Context context) { | |
this(context, null); | |
} | |
public FloatingActionsMenu(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
init(context, attrs); | |
} | |
public FloatingActionsMenu(Context context, AttributeSet attrs, int defStyle) { | |
super(context, attrs, defStyle); | |
init(context, attrs); | |
} | |
private void init(Context context, AttributeSet attributeSet) { | |
mButtonSpacing = (int) (getResources().getDimension( | |
R.dimen.fab_actions_spacing) | |
- getResources().getDimension(R.dimen.fab_shadow_radius) - getResources() | |
.getDimension(R.dimen.fab_shadow_offset)); | |
mLabelsMargin = getResources().getDimensionPixelSize( | |
R.dimen.fab_labels_margin); | |
mLabelsVerticalOffset = getResources().getDimensionPixelSize( | |
R.dimen.fab_shadow_offset); | |
TypedArray attr = context.obtainStyledAttributes(attributeSet, | |
R.styleable.FloatingActionsMenu, 0, 0); | |
mAddButtonPlusColor = attr.getColor( | |
R.styleable.FloatingActionsMenu_fab_addButtonPlusIconColor, | |
getColor(android.R.color.white)); | |
mAddButtonColorNormal = attr.getColor( | |
R.styleable.FloatingActionsMenu_fab_addButtonColorNormal, | |
getColor(android.R.color.holo_blue_dark)); | |
mAddButtonColorPressed = attr.getColor( | |
R.styleable.FloatingActionsMenu_fab_addButtonColorPressed, | |
getColor(android.R.color.holo_blue_light)); | |
mExpandDirection = attr.getInt( | |
R.styleable.FloatingActionsMenu_fab_expandDirection, EXPAND_UP); | |
mLabelsStyle = attr.getResourceId( | |
R.styleable.FloatingActionsMenu_fab_labelStyle, 0); | |
attr.recycle(); | |
if (mLabelsStyle != 0 && expandsHorizontally()) { | |
throw new IllegalStateException( | |
"Action labels in horizontal expand orientation is not supported."); | |
} | |
createAddButton(context); | |
} | |
private boolean expandsHorizontally() { | |
return mExpandDirection == EXPAND_LEFT | |
|| mExpandDirection == EXPAND_RIGHT; | |
} | |
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(); | |
} | |
} | |
private void createAddButton(Context context) { | |
mAddButton = new AddFloatingActionButton(context) { | |
@Override | |
void updateBackground() { | |
mPlusColor = mAddButtonPlusColor; | |
mColorNormal = mAddButtonColorNormal; | |
mColorPressed = mAddButtonColorPressed; | |
super.updateBackground(); | |
} | |
@Override | |
Drawable getIconDrawable() { | |
final RotatingDrawable rotatingDrawable = new RotatingDrawable( | |
super.getIconDrawable()); | |
mRotatingDrawable = rotatingDrawable; | |
final OvershootInterpolator interpolator = new OvershootInterpolator(); | |
final ObjectAnimator collapseAnimator = ObjectAnimator.ofFloat( | |
rotatingDrawable, "rotation", EXPANDED_PLUS_ROTATION, | |
COLLAPSED_PLUS_ROTATION); | |
final ObjectAnimator expandAnimator = ObjectAnimator.ofFloat( | |
rotatingDrawable, "rotation", COLLAPSED_PLUS_ROTATION, | |
EXPANDED_PLUS_ROTATION); | |
collapseAnimator.setInterpolator(interpolator); | |
expandAnimator.setInterpolator(interpolator); | |
mExpandAnimation.play(expandAnimator); | |
mCollapseAnimation.play(collapseAnimator); | |
return rotatingDrawable; | |
} | |
}; | |
mAddButton.setId(R.id.fab_expand_menu_button); | |
mAddButton.setOnClickListener(new OnClickListener() { | |
@Override | |
public void onClick(View v) { | |
toggle(); | |
} | |
}); | |
addView(mAddButton, super.generateDefaultLayoutParams()); | |
} | |
public void addButton(FloatingActionButton button) { | |
addView(button, mButtonsCount - 1); | |
mButtonsCount++; | |
if (mLabelsStyle != 0) { | |
createLabels(); | |
} | |
} | |
private int getColor(@ColorRes int id) { | |
return getResources().getColor(id); | |
} | |
@Override | |
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | |
measureChildren(widthMeasureSpec, heightMeasureSpec); | |
int width = 0; | |
int height = 0; | |
int maxLabelWidth = 0; | |
for (int i = 0; i < mButtonsCount; i++) { | |
View child = getChildAt(i); | |
switch (mExpandDirection) { | |
case EXPAND_UP: | |
case EXPAND_DOWN: | |
width = Math.max(width, child.getMeasuredWidth()); | |
height += child.getMeasuredHeight(); | |
break; | |
case EXPAND_LEFT: | |
case EXPAND_RIGHT: | |
width += child.getMeasuredWidth(); | |
height = Math.max(height, child.getMeasuredHeight()); | |
break; | |
} | |
if (!expandsHorizontally()) { | |
TextView label = (TextView) child.getTag(R.id.fab_label); | |
if (label != null) { | |
maxLabelWidth = Math.max(maxLabelWidth, | |
label.getMeasuredWidth()); | |
} | |
} | |
} | |
if (!expandsHorizontally()) { | |
width += maxLabelWidth + mLabelsMargin; | |
} | |
switch (mExpandDirection) { | |
case EXPAND_UP: | |
case EXPAND_DOWN: | |
height += mButtonSpacing * (getChildCount() - 1); | |
height = adjustForOvershoot(height); | |
break; | |
case EXPAND_LEFT: | |
case EXPAND_RIGHT: | |
width += mButtonSpacing * (getChildCount() - 1); | |
width = adjustForOvershoot(width); | |
break; | |
} | |
setMeasuredDimension(width, height); | |
} | |
private int adjustForOvershoot(int dimension) { | |
return dimension * 12 / 10; | |
} | |
@Override | |
protected void onLayout(boolean changed, int l, int t, int r, int b) { | |
switch (mExpandDirection) { | |
case EXPAND_UP: | |
case EXPAND_DOWN: | |
boolean expandUp = mExpandDirection == EXPAND_UP; | |
int addButtonY = expandUp ? b - t - mAddButton.getMeasuredHeight() | |
: 0; | |
int addButtonLeft = r - l - mAddButton.getMeasuredWidth(); | |
mAddButton.layout(addButtonLeft, addButtonY, addButtonLeft | |
+ mAddButton.getMeasuredWidth(), | |
addButtonY + mAddButton.getMeasuredHeight()); | |
int labelsRight = addButtonLeft - mLabelsMargin; | |
int nextY = expandUp ? addButtonY - mButtonSpacing : addButtonY | |
+ mAddButton.getMeasuredHeight() + mButtonSpacing; | |
for (int i = mButtonsCount - 1; i >= 0; i--) { | |
final View child = getChildAt(i); | |
if (child == mAddButton) | |
continue; | |
int childX = addButtonLeft | |
+ (mAddButton.getMeasuredWidth() - child | |
.getMeasuredWidth()) / 2; | |
int childY = expandUp ? nextY - child.getMeasuredHeight() | |
: nextY; | |
child.layout(childX, childY, childX + child.getMeasuredWidth(), | |
childY + child.getMeasuredHeight()); | |
float collapsedTranslation = addButtonY - childY; | |
float expandedTranslation = 0f; | |
ViewHelper.setTranslationY(child, | |
mExpanded ? expandedTranslation : collapsedTranslation); | |
// child.setTranslationY(mExpanded ? expandedTranslation : | |
// collapsedTranslation); | |
ViewHelper.setAlpha(child, mExpanded ? 1f : 0f); | |
// child.setAlpha(mExpanded ? 1f : 0f); | |
LayoutParams params = (LayoutParams) child.getLayoutParams(); | |
params.mCollapseDir.setFloatValues(expandedTranslation, | |
collapsedTranslation); | |
params.mExpandDir.setFloatValues(collapsedTranslation, | |
expandedTranslation); | |
params.setAnimationsTarget(child); | |
View label = (View) child.getTag(R.id.fab_label); | |
if (label != null) { | |
int labelLeft = labelsRight - label.getMeasuredWidth(); | |
int labelTop = childY | |
- mLabelsVerticalOffset | |
+ (child.getMeasuredHeight() - label | |
.getMeasuredHeight()) / 2; | |
label.layout(labelLeft, labelTop, labelsRight, labelTop | |
+ label.getMeasuredHeight()); | |
ViewHelper.setTranslationY(label, | |
mExpanded ? expandedTranslation | |
: collapsedTranslation); | |
// label.setTranslationY(mExpanded ? expandedTranslation : | |
// collapsedTranslation); | |
ViewHelper.setAlpha(label, mExpanded ? 1f : 0f); | |
// label.setAlpha(mExpanded ? 1f : 0f); | |
LayoutParams labelParams = (LayoutParams) label | |
.getLayoutParams(); | |
labelParams.mCollapseDir.setFloatValues( | |
expandedTranslation, collapsedTranslation); | |
labelParams.mExpandDir.setFloatValues(collapsedTranslation, | |
expandedTranslation); | |
labelParams.setAnimationsTarget(label); | |
} | |
nextY = expandUp ? childY - mButtonSpacing : childY | |
+ child.getMeasuredHeight() + mButtonSpacing; | |
} | |
break; | |
case EXPAND_LEFT: | |
case EXPAND_RIGHT: | |
boolean expandLeft = mExpandDirection == EXPAND_LEFT; | |
int addButtonX = expandLeft ? r - l - mAddButton.getMeasuredWidth() | |
: 0; | |
mAddButton.layout(addButtonX, 0, | |
addButtonX + mAddButton.getMeasuredWidth(), | |
mAddButton.getMeasuredHeight()); | |
int nextX = expandLeft ? addButtonX - mButtonSpacing : addButtonX | |
+ mAddButton.getMeasuredWidth() + mButtonSpacing; | |
for (int i = mButtonsCount - 1; i >= 0; i--) { | |
final View child = getChildAt(i); | |
if (child == mAddButton) | |
continue; | |
int childX = expandLeft ? nextX - child.getMeasuredWidth() | |
: nextX; | |
int childY = (mAddButton.getMeasuredHeight() - child | |
.getMeasuredHeight()) / 2; | |
child.layout(childX, childY, childX + child.getMeasuredWidth(), | |
childY + child.getMeasuredHeight()); | |
float collapsedTranslation = addButtonX - childX; | |
float expandedTranslation = 0f; | |
ViewHelper.setTranslationY(child, | |
mExpanded ? expandedTranslation : collapsedTranslation); | |
ViewHelper.setAlpha(child, mExpanded ? 1f : 0f); | |
// child.setTranslationX(mExpanded ? expandedTranslation : | |
// collapsedTranslation); | |
// child.setAlpha(mExpanded ? 1f : 0f); | |
LayoutParams params = (LayoutParams) child.getLayoutParams(); | |
params.mCollapseDir.setFloatValues(expandedTranslation, | |
collapsedTranslation); | |
params.mExpandDir.setFloatValues(collapsedTranslation, | |
expandedTranslation); | |
params.setAnimationsTarget(child); | |
nextX = expandLeft ? childX - mButtonSpacing : childX | |
+ child.getMeasuredWidth() + mButtonSpacing; | |
} | |
break; | |
} | |
} | |
@Override | |
protected ViewGroup.LayoutParams generateDefaultLayoutParams() { | |
return new LayoutParams(super.generateDefaultLayoutParams()); | |
} | |
@Override | |
public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { | |
return new LayoutParams(super.generateLayoutParams(attrs)); | |
} | |
@Override | |
protected ViewGroup.LayoutParams generateLayoutParams( | |
ViewGroup.LayoutParams p) { | |
return new LayoutParams(super.generateLayoutParams(p)); | |
} | |
@Override | |
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { | |
return super.checkLayoutParams(p); | |
} | |
private static Interpolator sExpandInterpolator = new OvershootInterpolator(); | |
private static Interpolator sCollapseInterpolator = new DecelerateInterpolator( | |
3f); | |
private static Interpolator sAlphaExpandInterpolator = new DecelerateInterpolator(); | |
private class LayoutParams extends ViewGroup.LayoutParams { | |
private ObjectAnimator mExpandDir = new ObjectAnimator(); | |
private ObjectAnimator mExpandAlpha = new ObjectAnimator(); | |
private ObjectAnimator mCollapseDir = new ObjectAnimator(); | |
private ObjectAnimator mCollapseAlpha = new ObjectAnimator(); | |
public LayoutParams(ViewGroup.LayoutParams source) { | |
super(source); | |
mExpandDir.setInterpolator(sExpandInterpolator); | |
mExpandAlpha.setInterpolator(sAlphaExpandInterpolator); | |
mCollapseDir.setInterpolator(sCollapseInterpolator); | |
mCollapseAlpha.setInterpolator(sCollapseInterpolator); | |
// mCollapseAlpha.setProperty(View.ALPHA); | |
mCollapseAlpha.setPropertyName("alpha"); | |
mCollapseAlpha.setFloatValues(1f, 0f); | |
// mExpandAlpha.setProperty(View.ALPHA); | |
mExpandAlpha.setPropertyName("alpha"); | |
mExpandAlpha.setFloatValues(0f, 1f); | |
switch (mExpandDirection) { | |
case EXPAND_UP: | |
case EXPAND_DOWN: | |
mCollapseDir.setPropertyName("translationY"); | |
// mCollapseDir.setProperty(View.TRANSLATION_Y); | |
mExpandDir.setPropertyName("translationY"); | |
// mExpandDir.setProperty(View.TRANSLATION_Y); | |
break; | |
case EXPAND_LEFT: | |
case EXPAND_RIGHT: | |
mCollapseDir.setPropertyName("translationX"); | |
// mCollapseDir.setProperty(View.TRANSLATION_X); | |
mExpandDir.setPropertyName("translationX"); | |
// mExpandDir.setProperty(View.TRANSLATION_X); | |
break; | |
} | |
mExpandAnimation.play(mExpandAlpha); | |
mExpandAnimation.play(mExpandDir); | |
mCollapseAnimation.play(mCollapseAlpha); | |
mCollapseAnimation.play(mCollapseDir); | |
} | |
public void setAnimationsTarget(View view) { | |
mCollapseAlpha.setTarget(view); | |
mCollapseDir.setTarget(view); | |
mExpandAlpha.setTarget(view); | |
mExpandDir.setTarget(view); | |
} | |
} | |
@Override | |
protected void onFinishInflate() { | |
super.onFinishInflate(); | |
bringChildToFront(mAddButton); | |
mButtonsCount = getChildCount(); | |
if (mLabelsStyle != 0) { | |
createLabels(); | |
} | |
} | |
private void createLabels() { | |
Context context = new ContextThemeWrapper(getContext(), mLabelsStyle); | |
for (int i = 0; i < mButtonsCount; i++) { | |
FloatingActionButton button = (FloatingActionButton) getChildAt(i); | |
String title = button.getTitle(); | |
if (button == mAddButton || title == null | |
|| button.getTag(R.id.fab_label) != null) | |
continue; | |
TextView label = new TextView(context); | |
label.setText(button.getTitle()); | |
addView(label); | |
button.setTag(R.id.fab_label, label); | |
} | |
} | |
public void collapse() { | |
if (mExpanded) { | |
mExpanded = false; | |
mCollapseAnimation.start(); | |
mExpandAnimation.cancel(); | |
} | |
} | |
public void toggle() { | |
if (mExpanded) { | |
collapse(); | |
} else { | |
expand(); | |
} | |
} | |
public void expand() { | |
if (!mExpanded) { | |
mExpanded = true; | |
mCollapseAnimation.cancel(); | |
mExpandAnimation.start(); | |
} | |
} | |
public boolean isExpanded() { | |
return mExpanded; | |
} | |
@Override | |
public Parcelable onSaveInstanceState() { | |
Parcelable superState = super.onSaveInstanceState(); | |
SavedState savedState = new SavedState(superState); | |
savedState.mExpanded = mExpanded; | |
return savedState; | |
} | |
@Override | |
public void onRestoreInstanceState(Parcelable state) { | |
if (state instanceof SavedState) { | |
SavedState savedState = (SavedState) state; | |
mExpanded = savedState.mExpanded; | |
if (mRotatingDrawable != null) { | |
mRotatingDrawable | |
.setRotation(mExpanded ? EXPANDED_PLUS_ROTATION | |
: COLLAPSED_PLUS_ROTATION); | |
} | |
super.onRestoreInstanceState(savedState.getSuperState()); | |
} else { | |
super.onRestoreInstanceState(state); | |
} | |
} | |
public static class SavedState extends BaseSavedState { | |
public boolean mExpanded; | |
public SavedState(Parcelable parcel) { | |
super(parcel); | |
} | |
private SavedState(Parcel in) { | |
super(in); | |
mExpanded = in.readInt() == 1; | |
} | |
@Override | |
public void writeToParcel(@NonNull Parcel out, int flags) { | |
super.writeToParcel(out, flags); | |
out.writeInt(mExpanded ? 1 : 0); | |
} | |
public static final Creator<SavedState> CREATOR = new Creator<SavedState>() { | |
@Override | |
public SavedState createFromParcel(Parcel in) { | |
return new SavedState(in); | |
} | |
@Override | |
public SavedState[] newArray(int size) { | |
return new SavedState[size]; | |
} | |
}; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment