it-swarm.asia

Android için Google+ uygulamasında olduğu gibi FloatingActionButton'a nasıl animasyon uygulayabilirsiniz?

FloatingActionButton öğesini ekranın altına ayarladım ve düğmeyi canlandırmak istiyorum.

  • Aşağı kaydırırken gizli
  • Yukarı kaydırırken gösterilir

Google'ın Google+ uygulamasında uyguladığı gibi.

Bence CoordinatorLayout ve AppBarLayout gerekli ama FloatingActionButton ile kullanmak için nasıl uygulanmalı?

17
Mehrdad Faraji

app:layout_behavior niteliğini kullanarak varsayılan FloatingActionButton işlevini değiştirerek Default Behavior işlevini kullanarak elde edebilirsiniz:

Gibi bir düzen kullanabilirsiniz:

 <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 ile kendi Behavior'ınızı tanımlayabilirsiniz. onStartNestedScroll() ve onNestedScroll() yöntemleriyle kaydırma olaylarıyla etkileşime girebilirsiniz.

Bunun gibi bir davranış kullanabilirsiniz . Orijinal kodu bulabilirsiniz burada:

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

Bu gönderiden itibaren, Tasarım Destek Kitaplıkları'ndaki FloatingActionButton değerini gizlemeyi ve göstermeyi otomatik olarak yapacak hiçbir yöntem yoktur. Bunu biliyorum çünkü bu benim iş yerindeki ilk görevimdi.

Düşündüğünüz yöntemler, FloatingActionButton oluşturulduğunda Snackbar yukarı ve aşağı hareketlerini canlandırmak için kullanılır ve evet, CoordinatorLayout kullanıyorsanız işe yarar.

İşte kodum. this repo'dan kaynaklanmaktadır. Düğmeyi otomatik olarak harekete geçiren RecyclerView ve AbsListView dinleyicileri vardır. Ya yapabilirsin

button.show();

veya

button.hide();

düğmesini el ile gizlemek veya

button.attachToListView(listView);

ve

button.attachToRecyclerView(recyclerView);

ve aşağı kaydırırken gizlenecek ve başka bir kod olmadan kaydırmada gösterilecektir.

Bu yardımcı olur umarım!

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 Tasarım Destek Kütüphanesi bunu yapacak.

Bu kodu mizanpaj dosyanıza uygulamaya çalışın:

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

Build.gradle için compile 'com.Android.support:design:22.2.0' eklemeniz önemlidir. Eclipse orada kullanıyorsanız başka bir yol bu kitaplığı projenize eklemek için.

Önemli kaynaklar:
Tasarım Destek Kütüphanesi (II): Yüzen Eylem Düğmesi
Android Tasarım Destek Kütüphanesi
Google, Muhteşem Bir Yeni Tasarım Destek Kütüphanesi Yayınladı [Güncelleme]

0
Tomblarom