2015-07-17 15 views
5

Stavo facendo ricerche su come creare un menu di azione mobile con i pulsanti di azione mobili (FAB) e mi sono imbattuto nello this question. Nei commenti, il commento di this ha fornito una classe che offriva l'opzione FloatingActionMenu. Ho implementato la classe e il file xml e funziona con un solo problema.Classe FloatingAction Aggiungi spaziatura tra i pulsanti

Edizione: Nel menu ci sono quattro FAB, il primo è il pulsante su cui si fa clic per espandere il menu. Tra tutti i FAB vorrei che ci fosse una spaziatura, tuttavia, non c'è spazio e non posso aggiungerne nessuno. (Vedi immagine sotto)

FAB without margin

FloatingActionMenu Classe

public class FloatingActionMenu extends ViewGroup { 

    private static final long ANIMATION_DURATION = 300; 
    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 static final int DEFAULT_CHILD_GRAVITY = Gravity.END | Gravity.BOTTOM; 
    private ImageView mIcon; 
    private boolean mOpen; 
    private boolean animating; 
    private boolean mIsSetClosedOnTouchOutside = true; 

    public interface OnMenuToggleListener { 
     void onMenuToggle(boolean opened); 
    } 

    public interface OnMenuItemClickListener { 
     void onMenuItemClick(FloatingActionMenu fam, int index, FloatingActionButton item); 
    } 


    private OnMenuItemClickListener onMenuItemClickListener; 
    private OnMenuToggleListener onMenuToggleListener; 

    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(null); 
      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(); 
     } 
    } 

    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()); 
     button.setBackgroundResource(R.drawable.rounded_corners); 
     button.setPadding(8,8,8,8); 
     button.setTextColor(Color.WHITE); 
     button.setText(item.getContentDescription()); 
     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; 
     } 
     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; 
     } 

     setMeasuredDimension(resolveSize(width, widthMeasureSpec), 
       resolveSize(height, heightMeasureSpec)); 
    } 

// 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; 
// } 

    @Override 
    public boolean onTouchEvent(@NonNull 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(); 
        return true; 
       } 
      }); 

    @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; 
       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()); 
       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); 
    } 

    static final TimeInterpolator DEFAULT_OPEN_INTERPOLATOR = new OvershootInterpolator(); 
    static final TimeInterpolator DEFAULT_CLOSE_INTERPOLATOR = new AnticipateInterpolator(); 

    public boolean isOpened() { 
     return mOpen; 
    } 

    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(); 
     } 

     public void startCloseAnimator() { 
      mView.animate().cancel(); 
      playingOpenAnimator = false; 
      mView.animate().translationY((mMenuButton.getTop() - mView.getTop())).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) { 
     } 
    } 


    @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"); 
     } 
    } 

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

L'XML Menu: codice

<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:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:src="@drawable/search" 
     android:paddingBottom="@dimen/menu_button_margin" 
     fab:fabSize="normal" 
     android:id="@+id/fab_main" /> 

    <!-- 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:src="@drawable/random" 
     android:paddingBottom="@dimen/menu_button_margin" 
     fab:fabSize="mini"/> 


    <android.support.design.widget.FloatingActionButton 
     android:id="@+id/fab_search" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:contentDescription="@string/default_search" 
     android:src="@drawable/search" 
     android:paddingBottom="@dimen/menu_button_margin" 
     fab:fabSize="mini"/> 

    <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:src="@drawable/browseropen" 
     android:paddingBottom="@dimen/menu_button_margin" 
     fab:fabSize="mini"/> 

</terranovaproductions.newcomicreader.FloatingActionMenu> 

Questo XML è in un RelativeLayout con altri oggetti.

Quello che ho provato:

  1. Ho provato ad aggiungere imbottitura in XML per i singoli pulsanti
  2. Ho provato ad aggiungere i margini per i singoli pulsanti sia la classe e XML
  3. Ho cercato dove sono disegnati i pulsanti per trovare un modo per aggiungere spazio, ma non ho avuto fortuna.
+0

La classe lo fa, se ci guardi sono sicuro che puoi capirlo :) Guarda sotto l'interruttore() e apri() per vedere cosa succede. Ad esempio, mOpen è impostato su true. –

risposta

2

Sembra che questo codice ignori completamente il riempimento dell'articolo. Immagino che un modo veloce e sporco sarebbe semplicemente modificare il onLayout e inserire il codice hard del padding desiderato.

@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 -= 10; //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()); 
      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); 
      } 
     } 
    } 
} 
+0

Ha funzionato! Sapevo che il codice ignorava il padding, ma non ero sicuro di dove, grazie mille. Molti abbracci a te :) –

+0

Solo una nota, ho cambiato il bottom = top - = 10; line to bottom = top - = mMenuItems.get (i) .getPaddingBottom(); quindi posso solo impostare il padding del FAB. Se questo ha un senso –

Problemi correlati