| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542 |
- package terranovaproductions.newcomicreader;
- import android.animation.Animator;
- import android.animation.AnimatorSet;
- import android.animation.ObjectAnimator;
- import android.animation.TimeInterpolator;
- import android.animation.ValueAnimator;
- import android.content.Context;
- import android.graphics.Color;
- import android.graphics.drawable.ColorDrawable;
- import android.graphics.drawable.Drawable;
- import android.os.Bundle;
- import android.os.Parcelable;
- import android.support.annotation.NonNull;
- import android.support.design.widget.FloatingActionButton;
- import android.util.AttributeSet;
- import android.util.Log;
- import android.view.GestureDetector;
- import android.view.Gravity;
- import android.view.MotionEvent;
- import android.view.View;
- import android.view.ViewGroup;
- import android.view.animation.AnticipateInterpolator;
- import android.view.animation.OvershootInterpolator;
- import android.widget.ImageView;
- import android.widget.TextView;
- import java.util.ArrayList;
- /**
- * Created by charry on 2015/6/11. https://gist.github.com/douo/dfde289778a9b3b6918f and modified by Tristan Wiley
- */
- public class FloatingActionMenu extends ViewGroup {
- static final TimeInterpolator DEFAULT_OPEN_INTERPOLATOR = new OvershootInterpolator();
- static final TimeInterpolator DEFAULT_CLOSE_INTERPOLATOR = new AnticipateInterpolator();
- private static final long ANIMATION_DURATION = 300;
- private static final int DEFAULT_CHILD_GRAVITY = Gravity.END | Gravity.BOTTOM;
- Animator animator = new Animator() {
- @Override
- public long getStartDelay() {
- return 0;
- }
- @Override
- public void setStartDelay(long startDelay) {
- }
- @Override
- public Animator setDuration(long duration) {
- duration = 2;
- return null;
- }
- @Override
- public long getDuration() {
- return 0;
- }
- @Override
- public void setInterpolator(TimeInterpolator value) {
- }
- @Override
- public boolean isRunning() {
- return true;
- }
- };
- private FloatingActionButton mMenuButton;
- private ArrayList<FloatingActionButton> mMenuItems;
- private ArrayList<TextView> mMenuItemLabels;
- private ArrayList<ItemAnimator> mMenuItemAnimators;
- private int mItemMargin;
- private AnimatorSet mOpenAnimatorSet = new AnimatorSet();
- private AnimatorSet mCloseAnimatorSet = new AnimatorSet();
- private ImageView mIcon;
- private boolean mOpen;
- private boolean animating;
- private boolean mIsSetClosedOnTouchOutside = true;
- private OnMenuItemClickListener onMenuItemClickListener;
- private OnMenuToggleListener onMenuToggleListener;
- GestureDetector mGestureDetector = new GestureDetector(getContext(),
- new GestureDetector.SimpleOnGestureListener() {
- @Override
- public boolean onDown(MotionEvent e) {
- return mIsSetClosedOnTouchOutside && isOpened();
- }
- @Override
- public boolean onSingleTapUp(MotionEvent e) {
- close();
- return true;
- }
- });
- private OnClickListener mOnItemClickListener = new OnClickListener() {
- @Override
- public void onClick(View v) {
- if (v instanceof FloatingActionButton) {
- int i = mMenuItems.indexOf(v);
- if (onMenuItemClickListener != null) {
- onMenuItemClickListener.onMenuItemClick(FloatingActionMenu.this, i, (FloatingActionButton) v);
- }
- } else if (v instanceof TextView) {
- int i = mMenuItemLabels.indexOf(v);
- if (onMenuItemClickListener != null) {
- onMenuItemClickListener.onMenuItemClick(FloatingActionMenu.this, i, mMenuItems.get(i));
- }
- }
- close();
- }
- };
- public FloatingActionMenu(Context context) {
- this(context, null, 0);
- }
- public FloatingActionMenu(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
- public FloatingActionMenu(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- mMenuItems = new ArrayList<>(5);
- mMenuItemAnimators = new ArrayList<>(5);
- mMenuItemLabels = new ArrayList<>(5);
- mIcon = new ImageView(context);
- }
- @Override
- protected void onFinishInflate() {
- bringChildToFront(mMenuButton);
- bringChildToFront(mIcon);
- super.onFinishInflate();
- }
- @Override
- public void addView(@NonNull View child, int index, LayoutParams params) {
- super.addView(child, index, params);
- if (getChildCount() > 1) {
- if (child instanceof FloatingActionButton) {
- addMenuItem((FloatingActionButton) child);
- }
- } else {
- mMenuButton = (FloatingActionButton) child;
- mIcon.setImageDrawable(mMenuButton.getDrawable());
- addView(mIcon);
- mMenuButton.setImageDrawable(mMenuButton.getDrawable());
- createDefaultIconAnimation();
- mMenuButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- toggle();
- }
- });
- }
- }
- public void toggle() {
- if (!mOpen) {
- open();
- } else {
- close();
- }
- }
- public void open() {
- d("open");
- startOpenAnimator();
- mOpen = true;
- if (onMenuToggleListener != null) {
- onMenuToggleListener.onMenuToggle(true);
- }
- }
- public void close() {
- startCloseAnimator();
- mOpen = false;
- if (onMenuToggleListener != null) {
- onMenuToggleListener.onMenuToggle(true);
- }
- }
- protected void startCloseAnimator() {
- mCloseAnimatorSet.start();
- for (ItemAnimator anim : mMenuItemAnimators) {
- anim.startCloseAnimator();
- }
- }
- // Rect rect = new Rect();
- // Paint paint = new Paint();
- //
- // @Override
- // protected boolean drawChild(@NonNull Canvas canvas, @NonNull View child, long drawingTime) {
- // boolean b = super.drawChild(canvas, child, drawingTime);
- // paint.setColor(0xFFFF0000);
- // paint.setStyle(Paint.Style.STROKE);
- // rect.set(child.getLeft(), child.getTop(), child.getRight(), child.getBottom());
- // canvas.drawRect(rect, paint);
- // return b;
- // }
- protected void startOpenAnimator() {
- mOpenAnimatorSet.start();
- for (ItemAnimator anim : mMenuItemAnimators) {
- anim.startOpenAnimator();
- }
- }
- public void addMenuItem(FloatingActionButton item) {
- mMenuItems.add(item);
- mMenuItemAnimators.add(new ItemAnimator(item));
- TextView button = new TextView(getContext());
- LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
- button.setLayoutParams(params);
- button.setBackgroundResource(R.drawable.rounded_corners);
- button.setTextColor(Color.WHITE);
- button.setText(item.getContentDescription());
- Integer paddingSize = (int)button.getTextSize() / 3;
- button.setPadding(paddingSize, paddingSize, paddingSize, paddingSize);
- addView(button);
- mMenuItemLabels.add(button);
- item.setTag(button);
- item.setOnClickListener(mOnItemClickListener);
- button.setOnClickListener(mOnItemClickListener);
- }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int widthSize = MeasureSpec.getSize(widthMeasureSpec);
- int widthMode = MeasureSpec.getMode(widthMeasureSpec);
- int width;
- int heightSize = MeasureSpec.getSize(heightMeasureSpec);
- int heightMode = MeasureSpec.getMode(heightMeasureSpec);
- int height;
- final int count = getChildCount();
- int maxChildWidth = 0;
- for (int i = 0; i < count; i++) {
- View child = getChildAt(i);
- measureChild(child, widthMeasureSpec, heightMeasureSpec);
- }
- for (int i = 0; i < mMenuItems.size(); i++) {
- FloatingActionButton fab = mMenuItems.get(i);
- TextView label = mMenuItemLabels.get(i);
- maxChildWidth = Math.max(maxChildWidth, label.getMeasuredWidth() + fab.getMeasuredWidth() + mItemMargin);
- }
- maxChildWidth = Math.max(mMenuButton.getMeasuredWidth(), maxChildWidth);
- if (widthMode == MeasureSpec.EXACTLY) {
- width = widthSize;
- } else {
- width = maxChildWidth + 30;
- }
- if (heightMode == MeasureSpec.EXACTLY) {
- height = heightSize;
- } else {
- int heightSum = 0;
- for (int i = 0; i < count; i++) {
- View child = getChildAt(i);
- heightSum += child.getMeasuredHeight();
- }
- height = heightSum + 20;
- }
- setMeasuredDimension(resolveSize(width, widthMeasureSpec),
- resolveSize(height, heightMeasureSpec));
- }
- @Override
- public boolean onTouchEvent(@NonNull MotionEvent event) {
- if (mIsSetClosedOnTouchOutside) {
- return mGestureDetector.onTouchEvent(event);
- } else {
- return super.onTouchEvent(event);
- }
- }
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- System.out.println("onLayout:" + changed);
- if (changed) {
- int right = r - getPaddingRight();
- int bottom = b - getPaddingBottom();
- int top = bottom - mMenuButton.getMeasuredHeight();
- mMenuButton.layout(right - mMenuButton.getMeasuredWidth(), top, right, bottom);
- int dw = (mMenuButton.getMeasuredWidth() - mIcon.getMeasuredWidth()) / 2;
- int dh = (mMenuButton.getMeasuredHeight() - mIcon.getMeasuredHeight()) / 2;
- mIcon.layout(right - mIcon.getMeasuredWidth() - dw, bottom - mIcon.getMeasuredHeight() - dh, right - dw, bottom - dh);
- for (int i = 0; i < mMenuItems.size(); i++) {
- FloatingActionButton item = mMenuItems.get(i);
- TextView label = mMenuItemLabels.get(i);
- label.setBackgroundResource(R.drawable.rounded_corners);
- bottom = top -= mMenuItems.get(i).getPaddingBottom(); //Add 10px padding
- top -= item.getMeasuredHeight();
- int width = item.getMeasuredWidth();
- int d = (mMenuButton.getMeasuredWidth() - width) / 2;
- item.layout(right - width - d, top, right - d, bottom);
- d = (item.getMeasuredHeight() - label.getMeasuredHeight()) / 2;
- label.layout(item.getLeft() - mItemMargin - label.getMeasuredWidth() - 50, item.getTop() + d, item.getLeft() - mItemMargin, item.getTop() + d + label.getMeasuredHeight());
- if (!animating) {
- if (!mOpen) {
- item.setTranslationY(mMenuButton.getTop() - item.getTop());
- item.setVisibility(GONE);
- label.setVisibility(GONE);
- } else {
- item.setTranslationY(0);
- item.setVisibility(VISIBLE);
- label.setVisibility(VISIBLE);
- }
- }
- }
- if (!animating && getBackground() != null) {
- if (!mOpen) {
- getBackground().setAlpha(0);
- } else {
- getBackground().setAlpha(0xff);
- }
- }
- }
- }
- private void createDefaultIconAnimation() {
- Animator.AnimatorListener listener = new Animator.AnimatorListener() {
- @Override
- public void onAnimationStart(Animator animation) {
- animating = true;
- }
- @Override
- public void onAnimationEnd(Animator animation) {
- animating = false;
- }
- @Override
- public void onAnimationCancel(Animator animation) {
- animating = false;
- }
- @Override
- public void onAnimationRepeat(Animator animation) {
- }
- };
- ObjectAnimator collapseAnimator = ObjectAnimator.ofFloat(
- mIcon,
- "rotation",
- 135f,
- 0f
- );
- ObjectAnimator expandAnimator = ObjectAnimator.ofFloat(
- mIcon,
- "rotation",
- 0f,
- 135f
- );
- if (getBackground() != null) {
- ValueAnimator hideBackgroundAnimator = ObjectAnimator.ofInt(0xff, 0);
- hideBackgroundAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- Integer alpha = (Integer) animation.getAnimatedValue();
- //System.out.println(alpha);
- getBackground().setAlpha(alpha > 0xff ? 0xff : alpha);
- }
- });
- ValueAnimator showBackgroundAnimator = ObjectAnimator.ofInt(0, 0xff);
- showBackgroundAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- Integer alpha = (Integer) animation.getAnimatedValue();
- //System.out.println(alpha);
- getBackground().setAlpha(alpha > 0xff ? 0xff : alpha);
- }
- });
- mOpenAnimatorSet.playTogether(expandAnimator, showBackgroundAnimator);
- mCloseAnimatorSet.playTogether(collapseAnimator, hideBackgroundAnimator);
- } else {
- mOpenAnimatorSet.playTogether(expandAnimator);
- mCloseAnimatorSet.playTogether(collapseAnimator);
- }
- mOpenAnimatorSet.setInterpolator(DEFAULT_OPEN_INTERPOLATOR);
- mCloseAnimatorSet.setInterpolator(DEFAULT_CLOSE_INTERPOLATOR);
- mOpenAnimatorSet.setDuration(ANIMATION_DURATION);
- mCloseAnimatorSet.setDuration(ANIMATION_DURATION);
- mOpenAnimatorSet.addListener(listener);
- mCloseAnimatorSet.addListener(listener);
- }
- public boolean isOpened() {
- return mOpen;
- }
- @Override
- public Parcelable onSaveInstanceState() {
- d("onSaveInstanceState");
- Bundle bundle = new Bundle();
- bundle.putParcelable("instanceState", super.onSaveInstanceState());
- bundle.putBoolean("mOpen", mOpen);
- // ... save everything
- return bundle;
- }
- @Override
- public void onRestoreInstanceState(Parcelable state) {
- d("onRestoreInstanceState");
- if (state instanceof Bundle) {
- Bundle bundle = (Bundle) state;
- mOpen = bundle.getBoolean("mOpen");
- // ... load everything
- state = bundle.getParcelable("instanceState");
- }
- super.onRestoreInstanceState(state);
- }
- @Override
- protected void onDetachedFromWindow() {
- d("onDetachedFromWindow");
- //getBackground().setAlpha(bgAlpha);//reset default alpha
- super.onDetachedFromWindow();
- }
- @Override
- public void setBackground(Drawable background) {
- if (background instanceof ColorDrawable) {
- // after activity finish and relaucher , background drawable state still remain?
- int bgAlpha = Color.alpha(((ColorDrawable) background).getColor());
- d("bg:" + Integer.toHexString(bgAlpha));
- super.setBackground(background);
- } else {
- throw new IllegalArgumentException("floating only support color background");
- }
- }
- public OnMenuToggleListener getOnMenuToggleListener() {
- return onMenuToggleListener;
- }
- public void setOnMenuToggleListener(OnMenuToggleListener onMenuToggleListener) {
- this.onMenuToggleListener = onMenuToggleListener;
- }
- public OnMenuItemClickListener getOnMenuItemClickListener() {
- return onMenuItemClickListener;
- }
- public void setOnMenuItemClickListener(OnMenuItemClickListener onMenuItemClickListener) {
- this.onMenuItemClickListener = onMenuItemClickListener;
- }
- protected void d(String msg) {
- Log.d("FAM", msg == null ? null : msg);
- }
- public interface OnMenuToggleListener {
- void onMenuToggle(boolean opened);
- }
- public interface OnMenuItemClickListener {
- void onMenuItemClick(FloatingActionMenu fam, int index, FloatingActionButton item);
- }
- private class ItemAnimator implements Animator.AnimatorListener {
- private View mView;
- private boolean playingOpenAnimator;
- public ItemAnimator(View v) {
- v.animate().setListener(this);
- mView = v;
- }
- public void startOpenAnimator() {
- mView.animate().cancel();
- playingOpenAnimator = true;
- mView.animate().translationY(0).setInterpolator(DEFAULT_OPEN_INTERPOLATOR).start();
- mMenuButton.animate().rotation(135f).setInterpolator(DEFAULT_OPEN_INTERPOLATOR).start();
- }
- public void startCloseAnimator() {
- mView.animate().cancel();
- playingOpenAnimator = false;
- mView.animate().translationY((mMenuButton.getTop() - mView.getTop())).setInterpolator(DEFAULT_CLOSE_INTERPOLATOR).start();
- mMenuButton.animate().rotation(0f).setInterpolator(DEFAULT_CLOSE_INTERPOLATOR).start();
- }
- @Override
- public void onAnimationStart(Animator animation) {
- if (playingOpenAnimator) {
- mView.setVisibility(VISIBLE);
- } else {
- ((TextView) mView.getTag()).setVisibility(GONE);
- }
- }
- @Override
- public void onAnimationEnd(Animator animation) {
- if (!playingOpenAnimator) {
- mView.setVisibility(GONE);
- } else {
- ((TextView) mView.getTag()).setVisibility(VISIBLE);
- }
- }
- @Override
- public void onAnimationCancel(Animator animation) {
- }
- @Override
- public void onAnimationRepeat(Animator animation) {
- }
- }
- }
|