2015-09-05 4 views
22

私はFloatingActionMenuFloatingActionButtonsで作成するカスタムビューを使用しています。私はこのクラスをほぼ完全に動作させるように修正しました。最近シャドウを追加しようとすると、問題が発生しました。クラスは正方形にハードコーディングされているので、影が見えない四角形でカットされています。FloatingActionButtonシャドウを四角で囲む

は下の画像を参照してください:

FloatingActionButton

私が使用しているクラスは、私は、メニュー内の複数のFloatingActionButtons(Fabを)持つことができます。

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) { 
     } 
    } 
} 

マイレイアウト:ここで

がクラスである

<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> 

私は理解してFloatingActionMenuを行うには良い方法がありますが、私は多くを置くので、私はこの方法を選びましたそれに取り組む

私は余白を追加して、パディングを削除しようとしました。私は影を広げる方法を確信しています。私はかなり確信していますonLayout私は何かを変更する必要があります。

必要に応じてその他の情報を求めます。

+0

あなたはXMLを使い果たしましたか、それとも本当にRLの内部のFAMですか?私はあなたがMCVEのためにこれを短縮したと確信していますが、私は実際のXMLを投稿しようとします – AdamMc331

+0

他のものは無関係だったので、私はそれを短縮しました。ちょうど2つのTextViewとImageView –

+0

それは無関係かもしれません。なぜwrap_contentではなく、FAM match_parentの幅と高さがありますか?また、layout_gravityを使用せずに右下にどのようになっていますか? – AdamMc331

答えて

31

あなたのxmlレイアウトの親ビューに

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

を追加する必要があります。

+0

私はCoordinatorLayoutに追加しました。ありがとう。ありがとうございます。 – javaddroid

+0

適切なパディングを親ビューに適用することも考慮する必要があります。そうしないと、動作しません。 –

7

FloatingActionMenuから16dpのパディングを削除し、各FloatingActionButtonに16dpの余白を追加することができます。

+0

marginBottom = 16dpは私のために働いた – behelit

-2
を追加することにより、FABのデフォルト elevationをオーバーライド

android:elevation="0dp" 

やコードの呼び出しここでは詳細をご覧くださいView.setElevation(float)

How to remove FloatingActionButton's surrounding shadow?

+2

私は影を取り除きたいとは思わない、ちょうどそれを切らないようにする –

+0

これは決して助けにはならない。 OPはシャドウを取り除く方法を尋ねたのではなく、代わりに外観を改善する方法 – protectedmember

1

ボタンに余白を追加するだけです。 Orgazm pionerkiが提案したように。私は5dpを追加しました。これは問題ありません。

関連する問題