我將FloatingActionButton設置爲屏幕底部,我想爲按鈕設置動畫效果。如何在Google+應用中爲Android動畫效果FloatingActionButton?
-
向上滾動
像谷歌在其Google+ app實現它時,向下滾動
我認爲需要CoordinatorLayout和AppBarLayout,但是如何實現它以與FloatingActionButton一起使用?
我將FloatingActionButton設置爲屏幕底部,我想爲按鈕設置動畫效果。如何在Google+應用中爲Android動畫效果FloatingActionButton?
像谷歌在其Google+ app實現它時,向下滾動
我認爲需要CoordinatorLayout和AppBarLayout,但是如何實現它以與FloatingActionButton一起使用?
你可以使用默認的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);
}
}
}
爲什麼'RecyclerView'爲其'app:layout_behavior'屬性指定了一個字符串資源,而'FloatingActionButton'有一個文字,硬編碼的字符串?他們是否應該指向同一個「行爲」類? –
努力尋找'R.anim.fab_in'和'R.anim.fab_out'你能幫忙嗎?我認爲它沒有在存儲庫中提交。 –
我如何理解dyconsumed和dyunconsume? – Yaojin
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]
至於這個帖子,有沒有方法來自動處理隱藏和顯示的設計支持庫FloatingActionButton
。我知道這是因爲這是我第一份工作。
你正在考慮的方法被用來創建Snackbar
時動畫FloatingActionButton
上下,是的,那會如果您使用的是CoordinatorLayout
工作。
這是我的代碼。它基於this回購。它的收聽者爲RecyclerView
和AbsListView
,可以自動處理按鈕的動畫。您可以做
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);
}
}
@kevCron,坦克回答,但我使用ScrollView和我寫一個偵聽器像ScollListener類一樣上下滾動,但隱藏和顯示按鈕不順利,無論Google +應用程序是否具有良好的動畫效果和順利 –
@ 8m47x不,它不會't,FloatingActionButton沒有方法可以處理滾動時的隱藏。如果您閱讀Google尚未實施的文檔。 –
@MehrdadFaraji如果你的不流暢我建議你使用我的,我現在正在看它的工作,它非常流暢。或者你可以發佈你的代碼,我們可以檢查它,找出爲什麼它不光滑。 –
你也可以看看谷歌的BaseActivity的IO調度程序和相應的動畫工廠。 – Raghunandan