webentwicklung-frage-antwort-db.com.de

Wie animiere ich FloatingActionButton wie in der Google+ App für Android?

Ich setze FloatingActionButton am unteren Bildschirmrand und möchte die Schaltfläche animieren.

  • Beim Scrollen nach unten ausgeblendet
  • Wird beim Scrollen nach oben angezeigt

Wie Google es in ihrer Google+ App implementiert .

Ich denke, CoordinatorLayout und AppBarLayout werden benötigt, aber wie kann man es implementieren, um es mit dem FloatingActionButton zu verwenden?

17
Mehrdad Faraji

Sie können dies erreichen, indem Sie die Standardeinstellung FloatingActionButton verwenden und deren Standardeinstellung Behavior mithilfe des app:layout_behavior-Attributs ändern:

Sie können ein Layout wie folgt verwenden:

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

Mit dem app:layout_behavior können Sie Ihr eigenes Behavior definieren. Mit den Methoden onStartNestedScroll() und onNestedScroll() können Sie mit Scroll-Ereignissen interagieren.

Sie können ein Verhalten wie dieses verwenden .. _. Den Originalcode finden Sie hier:

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

In diesem Beitrag gibt es keine Methoden, mit denen automatisch die Variable FloatingActionButton in den Design Support Libraries versteckt und angezeigt wird. Ich weiß das, weil dies meine erste Aufgabe bei der Arbeit war.

Die Methoden, an die Sie denken, werden verwendet, um die FloatingActionButton beim Erstellen einer Snackbar nach oben und unten zu animieren, und ja, die funktionieren, wenn Sie eine CoordinatorLayout verwenden.

Hier ist mein Code. Es basiert auf this repo. Es gibt Listener für RecyclerView und AbsListView, die die Schaltfläche automatisch animieren. Sie können entweder tun

button.show();

oder

button.hide();

um die Schaltfläche manuell auszublenden, oder rufen Sie an:

button.attachToListView(listView);

und

button.attachToRecyclerView(recyclerView);

und es wird ausgeblendet beim Scrollen nach unten und beim Scrollen nach oben ohne weiteren Code.

Hoffe das hilft!

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);
}
}
5
Kevin Cronly

Googles Design Support Library wird dies tun.

Versuchen Sie, diesen Code in Ihre Layoutdatei zu implementieren:

<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 ist wichtig, dass Sie compile 'com.Android.support:design:22.2.0' zu Ihrem build.gradle hinzufügen. Wenn Sie Eclipse verwenden, können Sie diese Bibliothek mit ist ein anderer Weg zu Ihrem Projekt hinzufügen.

Wichtige Ressourcen:
Design Support Library (II): Floating-Aktionstaste
Android Design Support Library
Google veröffentlicht eine FABulous Support-Bibliothek für neues Design [aktualisiert]

0
Tomblarom