Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FloatingActionButton Shadow Cut by Square [duplicate]

I am using a custom view to create a FloatingActionMenu with FloatingActionButtons. I have modified this class to make it work almost perfectly, when trying to add a shadow recently I ran into an issue with it, the shadow is cut by an invisible square due to the class hardcoding it into a square, I believe.

See the below image:

FloatingActionButton

The class I am using is so I can have multiple FloatingActionButtons(FABs) in a menu.

Here is the class:

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 label = new TextView(getContext());           label.setBackgroundResource(R.drawable.rounded_corners);          label.setTextColor(Color.WHITE);         label.setText(item.getContentDescription());          Integer paddingSize = (int)label.getTextSize() / 3;          float scale = getResources().getDisplayMetrics().density;         int pxtodp = (int) (6*scale + 0.5f);          label.setPadding(paddingSize, paddingSize, paddingSize + pxtodp, paddingSize);          addView(label);         mMenuItemLabels.add(label);         item.setTag(label);         item.setOnClickListener(mOnItemClickListener);         label.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);                   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(), item.getTop() + d, item.getLeft() - mItemMargin, item.getTop() + d + label.getMeasuredHeight());                 label.setBackgroundResource(R.drawable.rounded_corners);                  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) {         }     } } 

My Layout:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:fab="http://schemas.android.com/apk/res-auto"     android:id="@+id/comicView"     android:layout_width="match_parent"     android:layout_height="match_parent"     android:background="@color/background_main"     android:orientation="vertical">      <terranovaproductions.newcomicreader.FloatingActionMenu         android:id="@+id/fab_menu"         android:layout_width="match_parent"         android:layout_height="match_parent"         android:padding="16dp"         >          <!--First button as menu button-->         <android.support.design.widget.FloatingActionButton             android:id="@+id/fab_main"             android:layout_width="wrap_content"             android:layout_height="wrap_content"             android:src="@drawable/ic_add_white_24dp"             fab:fabSize="normal"             fab:backgroundTint="@color/material_orange"             fab:borderWidth="0dp"             fab:elevation="6dp"/>          <!-- Other button as menu items-->         <android.support.design.widget.FloatingActionButton             android:id="@+id/fab_random"             android:layout_width="wrap_content"             android:layout_height="wrap_content"             android:contentDescription="@string/default_random"             android:paddingBottom="@dimen/menu_button_margin"             android:src="@drawable/ic_random"             fab:fabSize="mini"             fab:backgroundTint="@color/material_orange" />           <android.support.design.widget.FloatingActionButton             android:id="@+id/fab_download"             android:layout_width="wrap_content"             android:layout_height="wrap_content"             android:contentDescription="@string/download"             android:paddingBottom="@dimen/menu_button_margin"             android:src="@drawable/ic_download"             fab:fabSize="mini"             fab:backgroundTint="@color/material_orange"/>          <android.support.design.widget.FloatingActionButton             android:id="@+id/fab_browser"             android:layout_width="wrap_content"             android:layout_height="wrap_content"             android:contentDescription="@string/default_browser"             android:paddingBottom="@dimen/menu_button_margin"             android:src="@drawable/ic_open_browser"             fab:fabSize="mini"             fab:backgroundTint="@color/material_orange"/>      </terranovaproductions.newcomicreader.FloatingActionMenu>   </RelativeLayout> 

I understand there are better ways to do a FloatingActionMenu but I chose this way because I put a lot of work into it.

I have tried remove padding, adding a margin. I am unsure on how to make the shadow extend. I am pretty sure in the onLayout I need to change something.

Ask for any other information if needed.

like image 688
Tristan Wiley Avatar asked Sep 05 '15 22:09

Tristan Wiley


Video Answer


2 Answers

You need to add

android:clipChildren="false" android:clipToPadding="false" 

to the parent view in your xml layout.

like image 58
Justin Avatar answered Oct 09 '22 05:10

Justin


You can try to remove 16dp padding from FloatingActionMenu and add 16dp margin to each FloatingActionButton.

like image 24
Orgazm pionerki Avatar answered Oct 09 '22 03:10

Orgazm pionerki