android - How to animate both top and bottom Toolbars(or any other view) enter/exit screen on scroll in CoordinatorLayout? -
my activity contains 2 appbarlayouts in coordinatorlayout, 1 on top of screen, , other bottom. want make both of 2 appbarlayouts hide on scroll of recyclerview.
when there top one, it's easy make hide on scroll adding app:layout_scrollflags="scroll|enteralways"
toolbar, , app:layout_behavior="@string/appbar_scrolling_view_behavior"
container of recyclerview.
when there bottom appbarlayout hide on scroll, realized making custom behavior bottomappbarlayoutbehavior extends appbarlayout.behavior
.
however, when both of them made hide on scroll, succeed hide recyclerview shakes on scroll. , area of top toolbar leaves empty white space after hiding. below xml:
<android.support.design.widget.coordinatorlayout android:layout_width="match_parent" android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:android="http://schemas.android.com/apk/res/android"> <android.support.design.widget.appbarlayout android:layout_width="match_parent" android:layout_height="wrap_content"> <android.support.v7.widget.toolbar android:id="@+id/toptoolbar" android:layout_width="fill_parent" android:layout_height="wrap_content" app:layout_scrollflags="scroll|enteralways" /> </android.support.design.widget.appbarlayout> <framelayout android:layout_width="fill_parent" android:orientation="vertical" app:layout_behavior="@string/appbar_scrolling_view_behavior" android:id="@+id/recyclerviewcontainer" android:layout_height="fill_parent"/> <android.support.design.widget.appbarlayout android:layout_width="match_parent" android:layout_gravity="bottom" app:layout_behavior="mypackage.bottomappbarlayoutbehavior"> <linearlayout android:layout_width="match_parent" android:orientation="horizontal" android:layout_height="match_parent"> <!-- views --> </linearlayout> </android.support.design.widget.appbarlayout> </android.support.design.widget.coordinatorlayout>
below code of bottomappbarlayoutbehavior:
public class bottomappbarlayoutbehavior extends appbarlayout.behavior { private static final interpolator interpolator = new fastoutslowininterpolator(); private boolean misanimatingout = false; public bottomappbarlayoutbehavior(context context, attributeset attrs) { super(); } @override public boolean onstartnestedscroll(final coordinatorlayout coordinatorlayout, final appbarlayout child, final view directtargetchild, final view target, final int nestedscrollaxes) { return nestedscrollaxes == viewcompat.scroll_axis_vertical || super.onstartnestedscroll(coordinatorlayout, child, directtargetchild, target, nestedscrollaxes); } @override public void onnestedscroll(final coordinatorlayout coordinatorlayout, final appbarlayout 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) { animateout(child); } else if (dyconsumed < 0 && child.getvisibility() != view.visible) { animatein(child); } } private void animateout(final appbarlayout appbarlayout) { if (build.version.sdk_int >= 14) { viewcompat.animate(appbarlayout).translationy(168f).alpha(0.0f).setinterpolator(interpolator).withlayer() .setlistener(new viewpropertyanimatorlistener() { public void onanimationstart(view view) { bottomappbarlayoutbehavior.this.misanimatingout = true; } public void onanimationcancel(view view) { bottomappbarlayoutbehavior.this.misanimatingout = false; } public void onanimationend(view view) { bottomappbarlayoutbehavior.this.misanimatingout = false; view.setvisibility(view.gone); } }).start(); } else { animation anim = animationutils.loadanimation(appbarlayout.getcontext(), r.anim.fab_out); anim.setinterpolator(interpolator); anim.setduration(200l); anim.setanimationlistener(new animation.animationlistener() { public void onanimationstart(animation animation) { bottomappbarlayoutbehavior.this.misanimatingout = true; } public void onanimationend(animation animation) { bottomappbarlayoutbehavior.this.misanimatingout = false; appbarlayout.setvisibility(view.gone); } @override public void onanimationrepeat(final animation animation) { } }); appbarlayout.startanimation(anim); } } private void animatein(appbarlayout appbarlayout) { appbarlayout.setvisibility(view.visible); if (build.version.sdk_int >= 14) { viewcompat.animate(appbarlayout).scalex(1.0f).scaley(1.0f).alpha(1.0f) .setinterpolator(interpolator).withlayer().setlistener(null) .start(); } else { animation anim = animationutils.loadanimation(appbarlayout.getcontext(), r.anim.fab_in); anim.setduration(200l); anim.setinterpolator(interpolator); appbarlayout.startanimation(anim); } } }
i have found solution myself. appbarlayout
wrapper bottom linearlayout
redundant. remove appbarlayout
wrapper , make behavior
class extends coordinatorlayout.behavior<linearlayout>
. add behavior linearlayout
, top toolbar
, bottom linearlayout
enter , exit screen on scroll correctly.
the correct activity xml:
<android.support.design.widget.coordinatorlayout android:layout_width="match_parent" android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:android="http://schemas.android.com/apk/res/android"> <android.support.design.widget.appbarlayout android:layout_width="match_parent" android:layout_height="wrap_content"> <android.support.v7.widget.toolbar android:id="@+id/top_toolbar" android:layout_width="fill_parent" android:layout_height="wrap_content" app:layout_scrollflags="scroll|enteralways" /> </android.support.design.widget.appbarlayout> <framelayout android:layout_width="fill_parent" android:orientation="vertical" app:layout_behavior="@string/appbar_scrolling_view_behavior" android:id="@+id/recycler_view_container" android:layout_height="fill_parent"/> <linearlayout android:id="@+id/bottom_bar" android:layout_width="match_parent" android:orientation="horizontal" android:layout_height="wrap_content" android:layout_gravity="bottom" app:layout_behavior="*the_full_package_name*.linearlayoutbehavior "> <!-- child views --> </linearlayout> </android.support.design.widget.coordinatorlayout>
the correct behavior
class:
public class linearlayoutbehavior extends coordinatorlayout.behavior<linearlayout> { private static final interpolator interpolator = new fastoutslowininterpolator(); private boolean misanimatingout = false; public linearlayoutbehavior(context context, attributeset attrs) { super(); } @override public boolean onstartnestedscroll(final coordinatorlayout coordinatorlayout, final linearlayout child, final view directtargetchild, final view target, final int nestedscrollaxes) { return nestedscrollaxes == viewcompat.scroll_axis_vertical || super.onstartnestedscroll(coordinatorlayout, child, directtargetchild, target, nestedscrollaxes); } @override public void onnestedscroll(final coordinatorlayout coordinatorlayout, final linearlayout 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 , fab visible -> hide fab animateout(child); } else if (dyconsumed < 0 && child.getvisibility() != view.visible) { // user scrolled , fab not visible -> show fab animatein(child); } } private void animateout(final linearlayout linearlayout) { if (build.version.sdk_int >= 14) { viewcompat.animate(linearlayout).translationy(168f).alpha(0.0f).setinterpolator(interpolator).withlayer() .setlistener(new viewpropertyanimatorlistener() { public void onanimationstart(view view) { linearlayoutbehavior.this.misanimatingout = true; } public void onanimationcancel(view view) { linearlayoutbehavior.this.misanimatingout = false; } public void onanimationend(view view) { linearlayoutbehavior.this.misanimatingout = false; view.setvisibility(view.gone); } }).start(); } else { animation anim = animationutils.loadanimation(linearlayout.getcontext(), r.anim.fab_out); anim.setinterpolator(interpolator); anim.setduration(200l); anim.setanimationlistener(new animation.animationlistener() { public void onanimationstart(animation animation) { linearlayoutbehavior.this.misanimatingout = true; } public void onanimationend(animation animation) { linearlayoutbehavior.this.misanimatingout = false; linearlayout.setvisibility(view.gone); } @override public void onanimationrepeat(final animation animation) { } }); linearlayout.startanimation(anim); } } private void animatein(linearlayout linearlayout) { linearlayout.setvisibility(view.visible); if (build.version.sdk_int >= 14) { viewcompat.animate(linearlayout).translationy(0).scalex(1.0f).scaley(1.0f).alpha(1.0f) .setinterpolator(interpolator).withlayer().setlistener(null) .start(); } else { animation anim = animationutils.loadanimation(linearlayout.getcontext(), r.anim.fab_in); anim.setduration(200l); anim.setinterpolator(interpolator); linearlayout.startanimation(anim); } } }
Comments
Post a Comment