回答

31

你可以使用默認的FloatingActionButton改變其 默認實現它使用210 app:layout_behavior屬性:

您可以使用像一個佈局:

<android.support.design.widget.CoordinatorLayout  
     xmlns:android="http://schemas.android.com/apk/res/android" 
     xmlns:app="http://schemas.android.com/apk/res-auto" 
     android:id="@+id/main_content" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent"> 

    <android.support.design.widget.AppBarLayout 
     android:id="@+id/appbar" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> 

     <android.support.v7.widget.Toolbar 
      android:id="@+id/toolbar" 
      android:layout_width="match_parent" 
      android:layout_height="?attr/actionBarSize" 
      android:background="?attr/colorPrimary" 
      app:popupTheme="@style/ThemeOverlay.AppCompat.Light" 
      app:layout_scrollFlags="scroll|enterAlways" /> 

    </android.support.design.widget.AppBarLayout> 

    // Your layout, for example a RecyclerView 
    <RecyclerView 
     ..... 
     app:layout_behavior="@string/appbar_scrolling_view_behavior" /> 

    <android.support.design.widget.FloatingActionButton 
      android:id="@+id/fab" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_gravity="end|bottom" 
      android:layout_margin="@dimen/fab_margin" 
      android:src="@drawable/ic_done"  
      app:layout_behavior="com.support.android.designlibdemo.ScrollAwareFABBehavior" /> 

    </android.support.design.widget.CoordinatorLayout> 

隨着app:layout_behavior您可以定義自己的Behavior。通過onStartNestedScroll()onNestedScroll()方法,您可以與滾動事件進行交互。

您可以使用這樣的行爲。 你可以找到原代碼here:

public class ScrollAwareFABBehavior extends FloatingActionButton.Behavior { 
    private static final Interpolator INTERPOLATOR = new FastOutSlowInInterpolator(); 
    private boolean mIsAnimatingOut = false; 

    public ScrollAwareFABBehavior(Context context, AttributeSet attrs) { 
     super(); 
    } 

    @Override 
    public boolean onStartNestedScroll(final CoordinatorLayout coordinatorLayout, final FloatingActionButton child, 
             final View directTargetChild, final View target, final int nestedScrollAxes) { 
     // Ensure we react to vertical scrolling 
     return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL 
       || super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes); 
    } 

    @Override 
    public void onNestedScroll(final CoordinatorLayout coordinatorLayout, final FloatingActionButton child, 
           final View target, final int dxConsumed, final int dyConsumed, 
           final int dxUnconsumed, final int dyUnconsumed) { 
     super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed); 
     if (dyConsumed > 0 && !this.mIsAnimatingOut && child.getVisibility() == View.VISIBLE) { 
      // User scrolled down and the FAB is currently visible -> hide the FAB 
      animateOut(child); 
     } else if (dyConsumed < 0 && child.getVisibility() != View.VISIBLE) { 
      // User scrolled up and the FAB is currently not visible -> show the FAB 
      animateIn(child); 
     } 
    } 

    // Same animation that FloatingActionButton.Behavior uses to hide the FAB when the AppBarLayout exits 
    private void animateOut(final FloatingActionButton button) { 
     if (Build.VERSION.SDK_INT >= 14) { 
      ViewCompat.animate(button).scaleX(0.0F).scaleY(0.0F).alpha(0.0F).setInterpolator(INTERPOLATOR).withLayer() 
        .setListener(new ViewPropertyAnimatorListener() { 
         public void onAnimationStart(View view) { 
          ScrollAwareFABBehavior.this.mIsAnimatingOut = true; 
         } 

         public void onAnimationCancel(View view) { 
          ScrollAwareFABBehavior.this.mIsAnimatingOut = false; 
         } 

         public void onAnimationEnd(View view) { 
          ScrollAwareFABBehavior.this.mIsAnimatingOut = false; 
          view.setVisibility(View.GONE); 
         } 
        }).start(); 
     } else { 
      Animation anim = AnimationUtils.loadAnimation(button.getContext(), R.anim.fab_out); 
      anim.setInterpolator(INTERPOLATOR); 
      anim.setDuration(200L); 
      anim.setAnimationListener(new Animation.AnimationListener() { 
       public void onAnimationStart(Animation animation) { 
        ScrollAwareFABBehavior.this.mIsAnimatingOut = true; 
       } 

       public void onAnimationEnd(Animation animation) { 
        ScrollAwareFABBehavior.this.mIsAnimatingOut = false; 
        button.setVisibility(View.GONE); 
       } 

       @Override 
       public void onAnimationRepeat(final Animation animation) { 
       } 
      }); 
      button.startAnimation(anim); 
     } 
    } 

    // Same animation that FloatingActionButton.Behavior uses to show the FAB when the AppBarLayout enters 
    private void animateIn(FloatingActionButton button) { 
     button.setVisibility(View.VISIBLE); 
     if (Build.VERSION.SDK_INT >= 14) { 
      ViewCompat.animate(button).scaleX(1.0F).scaleY(1.0F).alpha(1.0F) 
        .setInterpolator(INTERPOLATOR).withLayer().setListener(null) 
        .start(); 
     } else { 
      Animation anim = AnimationUtils.loadAnimation(button.getContext(), R.anim.fab_in); 
      anim.setDuration(200L); 
      anim.setInterpolator(INTERPOLATOR); 
      button.startAnimation(anim); 
     } 
    } 
} 
+1

爲什麼'RecyclerView'爲其'app:layout_behavior'屬性指定了一個字符串資源,而'FloatingActionButton'有一個文字,硬編碼的字符串?他們是否應該指向同一個「行爲」類? –

+5

努力尋找'R.anim.fab_in'和'R.anim.fab_out'你能幫忙嗎?我認爲它沒有在存儲庫中提交。 –

+0

我如何理解dyconsumed和dyunconsume? – Yaojin

0

Googles Design Support Library會這樣做。

試圖實現這個代碼到你的佈局文件:

<android.support.design.widget.FloatingActionButton 
     android:id="@+id/fab" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:src="@drawable/ic_add_black" 
     android:layout_gravity="bottom|end" 
     app:elevation="6dp" 
     app:pressedTranslationZ="12dp"/> 

您添加compile 'com.android.support:design:22.2.0'到您的build.gradle是很重要的。如果您使用eclipse is another way將此庫添加到您的項目中。

重要的資源:
Design Support Library (II): Floating Action Button
Android Design Support Library
Google Releasing A FABulous New Design Support Library [Updated]

+0

儘管這個鏈接可能回答這個問題,但最好在這裏包含答案的重要部分,並提供供參考的鏈接。如果鏈接頁面更改,則僅鏈接答案可能會失效。 – gnat

+1

對不起。我真的必須這樣做。我是新來的stackoverflow;) – 8m47x

+2

@ 8m47x,坦克爲您的答案。但我不問如何創建FloatingActionButton,我創建和我使用了這個,我的問題是如何可以像谷歌+應用動畫FloatingActionButton? –

5

至於這個帖子,有沒有方法來自動處理隱藏和顯示的設計支持庫FloatingActionButton。我知道這是因爲這是我第一份工作。

你正在考慮的方法被用來創建Snackbar時動畫FloatingActionButton上下,是的,那會如果您使用的是CoordinatorLayout工作。

這是我的代碼。它基於this回購。它的收聽者爲RecyclerViewAbsListView,可以自動處理按鈕的動畫。您可以做

button.show(); 

button.hide(); 

手動隱藏按鈕,或者您也可以撥打:

button.attachToListView(listView); 

button.attachToRecyclerView(recyclerView); 

,它會隱藏向下滾動並顯示向上滾動而不顯示f更深的代碼。

希望這有助於!

AnimatedFloatingActionButton:

public class AnimatedFloatingActionButton extends FloatingActionButton 
{ 
    private static final int TRANSLATE_DURATION_MILLIS = 200; 
    private final Interpolator mInterpolator = new AccelerateDecelerateInterpolator(); 
    private boolean mVisible; 

public AnimatedFloatingActionButton(Context context, AttributeSet attrs) 
{ 
    super(context, attrs); 
    Log.i("Abscroll", "mVisible" + mVisible); 
} 

public void show() { 
    show(true); 
} 

public void hide() { 
    hide(true); 
} 

public void show(boolean animate) { 
    toggle(true, animate, false); 
} 

public void hide(boolean animate) { 
    toggle(false, animate, false); 
} 

private void toggle(final boolean visible, final boolean animate, boolean force) { 
    if (mVisible != visible || force) { 
     mVisible = visible; 
     int height = getHeight(); 
     if (height == 0 && !force) { 
      ViewTreeObserver vto = getViewTreeObserver(); 
      if (vto.isAlive()) { 
       vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { 
        @Override 
        public boolean onPreDraw() { 
         ViewTreeObserver currentVto = getViewTreeObserver(); 
         if (currentVto.isAlive()) { 
          currentVto.removeOnPreDrawListener(this); 
         } 
         toggle(visible, animate, true); 
         return true; 
        } 
       }); 
       return; 
      } 
     } 
     int translationY = visible ? 0 : height + getMarginBottom(); 
     Log.i("Abscroll", "transY" + translationY); 
     if (animate) { 
      this.animate().setInterpolator(mInterpolator) 
        .setDuration(TRANSLATE_DURATION_MILLIS) 
        .translationY(translationY); 
     } else { 
      setTranslationY(translationY); 
     } 
    } 
} 

private int getMarginBottom() { 
    int marginBottom = 0; 
    final ViewGroup.LayoutParams layoutParams = getLayoutParams(); 
    if (layoutParams instanceof ViewGroup.MarginLayoutParams) { 
     marginBottom = ((ViewGroup.MarginLayoutParams) layoutParams).bottomMargin; 
    } 
    return marginBottom; 
} 

public void attachToListView(@NonNull AbsListView listView) 
{ 
    listView.setOnScrollListener(new AbsListViewScrollDetector() { 
     @Override 
     void onScrollUp() { 
      hide(); 
     } 

     @Override 
     void onScrollDown() { 
      show(); 
     } 

     @Override 
     void setScrollThreshold() { 
      setScrollThreshold(getResources().getDimensionPixelOffset(R.dimen.fab_scroll_threshold)); 
     } 
    }); 
} 

public void attachToRecyclerView(@NonNull RecyclerView recyclerView) { 
    recyclerView.addOnScrollListener(new RecyclerViewScrollDetector() { 
     @Override 
     void onScrollUp() { 
      hide(); 
     } 

     @Override 
     void onScrollDown() { 
      show(); 
     } 

     @Override 
     void setScrollThreshold() { 
      setScrollThreshold(getResources().getDimensionPixelOffset(R.dimen.fab_scroll_threshold)); 
     } 
    }); 
} 
} 

AbsListViewScrollDetector:

abstract class AbsListViewScrollDetector implements AbsListView.OnScrollListener { 
private int mLastScrollY; 
private int mPreviousFirstVisibleItem; 
private AbsListView mListView; 
private int mScrollThreshold; 

abstract void onScrollUp(); 

abstract void onScrollDown(); 

abstract void setScrollThreshold(); 

@Override 
public void onScrollStateChanged(AbsListView view, int scrollState) { 
} 

@Override 
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { 
    if(totalItemCount == 0) return; 
    if (isSameRow(firstVisibleItem)) { 
     int newScrollY = getTopItemScrollY(); 
     boolean isSignificantDelta = Math.abs(mLastScrollY - newScrollY) > mScrollThreshold; 
     Log.i("Abscroll", "mLastScrollY " + mLastScrollY); 
     Log.i("Abscroll", "newScrollY " + newScrollY); 
     if (isSignificantDelta) { 
      Log.i("Abscroll", "sig delta"); 
      if (mLastScrollY > newScrollY) { 
       onScrollUp(); 
       Log.i("Abscroll", "sig delta up"); 
      } else { 
       onScrollDown(); 
       Log.i("Abscroll", "sig delta down"); 
      } 
     } 
     mLastScrollY = newScrollY; 
    } else { 
     if (firstVisibleItem > mPreviousFirstVisibleItem) { 
      onScrollUp(); 
      Log.i("Abscroll", "prev up"); 
     } else { 
      onScrollDown(); 
      Log.i("Abscroll", "prev down"); 
     } 

     mLastScrollY = getTopItemScrollY(); 
     mPreviousFirstVisibleItem = firstVisibleItem; 
    } 
} 

public void setScrollThreshold(int scrollThreshold) { 
    mScrollThreshold = scrollThreshold; 
    Log.i("Abscroll", "LView thresh " + scrollThreshold); 
} 

public void setListView(@NonNull AbsListView listView) { 
    mListView = listView; 
} 

private boolean isSameRow(int firstVisibleItem) { 
    return firstVisibleItem == mPreviousFirstVisibleItem; 
} 

private int getTopItemScrollY() { 
    if (mListView == null || mListView.getChildAt(0) == null) return 0; 
    View topChild = mListView.getChildAt(0); 
    return topChild.getTop(); 
} 
} 

RecyclerViewScrollDetector:

abstract class RecyclerViewScrollDetector extends RecyclerView.OnScrollListener { 
private int mScrollThreshold; 

abstract void onScrollUp(); 

abstract void onScrollDown(); 

abstract void setScrollThreshold(); 

@Override 
public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 
    boolean isSignificantDelta = Math.abs(dy) > mScrollThreshold; 
    if (isSignificantDelta) { 
     if (dy > 0) { 
      onScrollUp(); 
      Log.i("Abscroll", "Rview up"); 
     } else { 
      onScrollDown(); 
      Log.i("Abscroll", "RView down"); 
     } 
    } 
} 

public void setScrollThreshold(int scrollThreshold) { 
    mScrollThreshold = scrollThreshold; 
    Log.i("Abscroll", "RView thresh " + scrollThreshold); 
} 
} 
+0

@kevCron,坦克回答,但我使用ScrollView和我寫一個偵聽器像ScollListener類一樣上下滾動,但隱藏和顯示按鈕不順利,無論Google +應用程序是否具有良好的動畫效果和順利 –

+0

@ 8m47x不,它不會't,FloatingActionButton沒有方法可以處理滾動時的隱藏。如果您閱讀Google尚未實施的文檔。 –

+0

@MehrdadFaraji如果你的不流暢我建議你使用我的,我現在正在看它的工作,它非常流暢。或者你可以發佈你的代碼,我們可以檢查它,找出爲什麼它不光滑。 –

相關問題