How to animate FloatingActionButton like in Google+ app for Android?

匿名 (未验证) 提交于 2019-12-03 01:23:02

问题:

I set FloatingActionButton to bottom of screen and I want to animate the button.

  • Hidden when scrolling down
  • Shown when scrolling up

Like google implemented it in their Google+ app.

I think CoordinatorLayout and AppBarLayout is needed but how to implement it to use it with the FloatingActionButton?

回答1:

You can achieve it using the default FloatingActionButton changing its default Behavior using the app:layout_behavior attribute:

You can use a layout like:

       // Your layout, for example a RecyclerView     

With the app:layout_behavior you can define your own Behavior. With the onStartNestedScroll() and onNestedScroll() methods you can interact with scroll events.

You can use a Behavior like this. You can find the original code 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  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);         }     } } 


回答2:

As of this post, there are no methods that will automatically handle hiding and showing the FloatingActionButton in the Design Support Libraries. I know this because this was my first assignment at work.

The methods you are thinking of are used to animate the FloatingActionButton up and down when a Snackbar is created, and yes, that will work if you are using a CoordinatorLayout.

Here's my code. It's based off of this repo. It has listeners for RecyclerView and AbsListView that handle animating the button automatically. You can either do

button.show(); 

or

button.hide(); 

to hide the button manually, or you can call:

button.attachToListView(listView); 

and

button.attachToRecyclerView(recyclerView); 

and it will hide on scroll down and show on scroll up with no further code.

Hope this helps!

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


回答3:

Googles Design Support Library will do that.

Try to implement this code to your layout file:

It's important that you add compile 'com.android.support:design:22.2.0' to your build.gradle. If you're using eclipse there is another way to add this library to your project.

Important resources:
Design Support Library (II): Floating Action Button
Android Design Support Library
Google Releasing A FABulous New Design Support Library [Updated]



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!