icon floatingactionbutton extended bootstrap android android-animation material-design android-design-library floating-action-button

android - floatingactionbutton - floating action button onclick



¿Cómo animar FloatingActionButton como en la aplicación de Google+ para Android? (3)

A partir de esta publicación, no hay métodos que manejen automáticamente la ocultación y la visualización del FloatingActionButton de FloatingActionButton en las bibliotecas de soporte de diseño. Lo sé porque esta fue mi primera tarea en el trabajo.

Los métodos en los que está pensando se utilizan para animar el FloatingActionButton de FloatingActionButton hacia arriba y hacia abajo cuando se crea un Snackbar , y sí, eso funcionará si está utilizando un CoordinatorLayout .

Aquí está mi código. Se basa en this repositorio. Tiene escuchas para RecyclerView y AbsListView que manejan la animación del botón automáticamente. Usted puede hacer

button.show();

o

button.hide();

para ocultar el botón manualmente, o puede llamar:

button.attachToListView(listView);

y

button.attachToRecyclerView(recyclerView);

y se ocultará en el desplazamiento hacia abajo y se mostrará en el desplazamiento hacia arriba sin más código.

¡Espero que esto ayude!

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

Configuré FloatingActionButton en la parte inferior de la pantalla y quiero animar el botón.

  • Oculto cuando se desplaza hacia abajo
  • Se muestra cuando se desplaza hacia arriba

Como Google lo implementó en su aplicación de Google+ .

Pienso que CoordinatorLayout y AppBarLayout son necesarios, pero ¿cómo implementarlo para usarlo con el FloatingActionButton?


Googles Design Support Library lo hará.

Intenta implementar este código en tu archivo de diseño:

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

Es importante que agregue compile ''com.android.support:design:22.2.0'' a su build.gradle. Si está utilizando eclipse, existe otra forma de agregar esta biblioteca a su proyecto.

Recursos importantes:
Biblioteca de soporte de diseño (II): Botón de acción flotante
Biblioteca de soporte de diseño de Android
Google lanza una nueva y fabulosa biblioteca de soporte de diseño [actualizada]


Puede lograrlo utilizando el FloatingActionButton predeterminado cambiando su Behavior predeterminado utilizando el atributo app:layout_behavior :

Puede utilizar un diseño como:

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

Con la app:layout_behavior puedes definir tu propio Behavior . Con los onStartNestedScroll() y onNestedScroll() puede interactuar con eventos de desplazamiento.

Puede utilizar un comportamiento como este. Puedes encontrar el código original 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); } } }