FloatingActionButton under CoordiantorLayout is not animating - android

I am trying to animate the FloatingActionButton (Under CoordiantorLayout).When a user scrolls down a page, the floating action button should disappear. Once the page scrolls to the top, it should reappear.However it's not working as i expected Where do I mess up?
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/DrawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white"
android:elevation="7dp"
tools:context=".MainActivity">
<android.support.design.widget.CoordinatorLayout
android:id="#+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include
android:id="#+id/tool_bar"
layout="#layout/tool_bar"></include>
<android.support.v7.widget.RecyclerView
android:id="#+id/tripslist"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<android.support.design.widget.FloatingActionButton
android:id="#+id/createfab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:src="#drawable/ic_plus"
app:backgroundTint="#color/colorPrimary"
app:layout_behavior="mogo.trasome.views.ScrollAwareFABBehavior" />
</android.support.design.widget.CoordinatorLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/RecyclerView"
android:layout_width="320dp"
android:layout_height="match_parent"
android:layout_gravity="left"
android:background="#ffffff"
android:scrollbars="vertical" />
</android.support.v4.widget.DrawerLayout>
This is my Behavior class,
import android.content.Context;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.view.View;
public class ScrollAwareFABBehavior extends FloatingActionButton.Behavior {
public ScrollAwareFABBehavior(Context context, AttributeSet attrs) {
super();
}
#Override
public void onNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
if (child.getVisibility() == View.VISIBLE && dyConsumed > 0) {
child.hide();
} else if (child.getVisibility() == View.GONE && dyConsumed < 0) {
child.show();
}
}
#Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View directTargetChild, View target, int nestedScrollAxes) {
return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL;
}
}

Related

BottomNavigationView not hide on scrollview

iam new to android,please help me.
i want to hide bottom navigation bar so i am using bottom navigation behavior,
i have a scrollview when i scroll the bottomnavigationbar scrolls, i dosent hide please help me
morethan a week am trying to solve this issue please help me
MainActivity.java
mBottomNavigationView=findViewById(R.id.bottom_nav);
mBottomNavigationView = (BottomNavigationView) findViewById(R.id.bottom_nav);
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) mBottomNavigationView.getLayoutParams();
layoutParams.setBehavior(new BottomNavigationViewBehavior());
bottomNavigationView.setOnNavigationItemSelectedListener(
new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.bottombaritem_map:
........
......
return true;
}
return false;
}
});
}
BottomNavigationViewBehavior
public class BottomNavigationViewBehavior extends CoordinatorLayout.Behavior<BottomNavigationView> {
private int height;
#Override
public boolean onLayoutChild(CoordinatorLayout parent, BottomNavigationView child, int layoutDirection) {
height = child.getHeight();
return super.onLayoutChild(parent, child, layoutDirection);
}
#Override
public boolean onStartNestedScroll(#NonNull CoordinatorLayout coordinatorLayout,
BottomNavigationView child, #NonNull
View directTargetChild, #NonNull View target,
int axes, int type)
{
return axes == ViewCompat.SCROLL_AXIS_VERTICAL;
}
#Override
public void onNestedScroll(#NonNull CoordinatorLayout coordinatorLayout, #NonNull BottomNavigationView child,
#NonNull View target, int dxConsumed, int dyConsumed,
int dxUnconsumed, int dyUnconsumed,
#ViewCompat.NestedScrollType int type)
{
if (dyConsumed > 0) {
slideDown(child);
} else if (dyConsumed < 0) {
slideUp(child);
}
}
private void slideUp(BottomNavigationView child) {
child.clearAnimation();
child.animate().translationY(0).setDuration(200);
}
private void slideDown(BottomNavigationView child) {
child.clearAnimation();
child.animate().translationY(height).setDuration(200);
}
}
Layout xml file
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<android.support.design.widget.CoordinatorLayout
android:id="#+id/coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/main_book_scrol1"
android:layout_width="fill_parent"
android:visibility="visible"
android:layout_height="fill_parent"
android:fillViewport="true">
...........
..........
</ScrollView>
<!---your RecyclerView/Fragment Container Layout-->
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
<android.support.design.widget.BottomNavigationView
android:id="#+id/bottom_nav"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
app:itemBackground="#color/white"
app:menu="#menu/bottombar_menu" />
</android.support.design.widget.CoordinatorLayout>
<!---NavigationView-->
</android.support.v4.widget.DrawerLayout>

Show toolbar and bottom navigation view again

I have implemented show and hide functionality for toolbar and bottomNavigationView while scrolling up and down in recyclerView.
Now i click on recyclerView item and go to detail page which does not have recyclerView, now also toolbar and bottomNavigationView are hidden. Any method to make them visible again in this fragment.
main_activity.xml
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="#+id/tool_bar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:elevation="5dp"
android:theme="#style/ToolbarTheme"
app:layout_scrollFlags="scroll|enterAlways"
app:titleTextAppearance="#style/Toolbar.TitleText" />
</android.support.design.widget.AppBarLayout>
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
/>
<com.ittianyu.bottomnavigationviewex.BottomNavigationViewEx
android:id="#+id/bottom_navigation_bar"
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_alignParentBottom="true"
android:layout_gravity="bottom"
android:background="#drawable/menu_view"
android:isScrollContainer="false"
app:itemIconTint="#drawable/nav_item_color_state"
app:menu="#menu/my_navigation_items" />
BottomNavigationViewBehaviour.java
public class BottomNavigationViewBehavior extends CoordinatorLayout.Behavior<BottomNavigationView> {
private int height;
#Override
public boolean onLayoutChild(CoordinatorLayout parent, BottomNavigationView child, int layoutDirection) {
height = child.getHeight();
return super.onLayoutChild(parent, child, layoutDirection);
}
#Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, BottomNavigationView child,
View directTargetChild, View target, int nestedScrollAxes) {
return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL;
}
#Override
public void onNestedScroll(CoordinatorLayout coordinatorLayout, BottomNavigationView child, View target,
int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
if (dyConsumed > 0) {
slideDown(child);
} else if (dyConsumed < 0) {
slideUp(child);
}
}
private void slideUp(BottomNavigationView child) {
child.clearAnimation();
child.animate().translationY(0).setDuration(50);
}
private void slideDown(BottomNavigationView child) {
child.clearAnimation();
child.animate().translationY(height).setDuration(50);
}
}
MainActivity.java
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) mBottomNav.getLayoutParams();
layoutParams.setBehavior(new BottomNavigationViewBehavior());
mBottomNav.clearAnimation();
mBottomNav.animate().translationY(mBottomNav.getHeight()).setDuration(100);
you can use AppbarLayout to expand using appbarLayout.setExpand(true) but this only show your action bar not your bottomNavigationbar.

How to hide Floating Action Button on Nested Scroll

I'm trying to hide two FAB on Nested Scroll scrolling. I've tried to implement my own FAB behavior but it did't work. FAB's don't react on scrolling at all. Note: I deleted some part of layout to fit the post.
Layout
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="ru.berezin.maxim.im.budget_v3.userinterface.StartPage">
<android.support.design.widget.AppBarLayout
android:id="#+id/appcollapse"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:id="#+id/testingscroll"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none"
app:behavior_overlapTop="30dp"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<!--content including-->
<include layout="#layout/start_content_layout"/>
</android.support.v4.widget.NestedScrollView>
<android.support.design.widget.FloatingActionButton
android:id="#+id/start_page_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_margin="16dp"
android:src="#drawable/plus"
app:layout_anchor="#id/testingscroll"
app:layout_anchorGravity="end|bottom"
app:layout_behavior="ru.berezin.maxim.im.budget_v3.FabOnScroll"
/>
<View
android:id="#+id/dummy"
android:layout_width="1dp"
android:layout_height="16dp"
app:layout_anchor="#id/start_page_fab"
app:layout_anchorGravity="top|right|end"
/>
<android.support.design.widget.FloatingActionButton
android:id="#+id/account_det_add_transfer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|top"
android:layout_margin="16dp"
android:src="#drawable/minus"
app:layout_anchor="#id/dummy"
app:layout_anchorGravity="top|right|end"
app:layout_behavior="ru.berezin.maxim.im.budget_v3.FabOnScroll"
/>
</android.support.design.widget.CoordinatorLayout>
FabOnScroll class
public class FabOnScroll extends FloatingActionButton.Behavior {
public FabOnScroll(Context context, AttributeSet attrs) {
super();
}
#Override
public void onNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
//child -> Floating Action Button
if (dyConsumed > 0) {
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) child.getLayoutParams();
int fab_bottomMargin = layoutParams.bottomMargin;
child.animate().translationY(child.getHeight() + fab_bottomMargin).setInterpolator(new LinearInterpolator()).start();
} else if (dyConsumed < 0) {
child.animate().translationY(0).setInterpolator(new LinearInterpolator()).start();
}
}
#Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View directTargetChild, View target, int nestedScrollAxes) {
return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL;
}
}
So, I fixed it. Not exactly what I wanted, but it's working. I dont have any ideas why, but for some reason dyConsumed is always equals 0. But I noticed that dyUnconsumed is changing while I scroll. So I've just add dxUnconsumed check to my If/else statment and it's worked. Can someone explain why dyConsumed equals 0?
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener()
{
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy)
{
if (dy > 0 ||dy<0 && fab.isShown())
{
fab.hide();
}
}
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState)
{
if (newState == RecyclerView.SCROLL_STATE_IDLE)
{
fab.show();
}
super.onScrollStateChanged(recyclerView, newState);
}
});
I know it's a late answer but my solution is to use dyUnconsumed instead of dyConsumed inside the if statement and it worked very well with me
if (dyUnconsumed > 0 && child.getVisibility() == View.VISIBLE) {
child.hide(new FloatingActionButton.OnVisibilityChangedListener() {
#Override
public void onHidden(FloatingActionButton fab) {
super.onHidden(fab);
child.setVisibility(View.INVISIBLE);
}
});
} else if (dyUnconsumed <0 && child.getVisibility() != View.VISIBLE) {
child.show();
}

How to scroll up/down of bottom bar on scrolling of RecyclerView

With Google’s recent release of the Design Support Library several cool new views have been introduced. Using some of the new components (e.g. CoordinatorLayout ) might (!) enable you to achieve the scrolling behavior.
I was tryed with some built in scrolling behavior but nothing is working for me,
I have a bottombar(LinearLayout) in my layout in place of FloatingActionButton
Here what I want.
OnLaunch of this screen bottom bar should appear.
On scrollup of recyclerview bottom bar should scrolldown.
On scrolldown of recyclerview bottom bar should scrollup
Is there any builtin mechanism to achieve this ? or We need write java code?
Here is my code:
main_activty.xml
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<include layout="#layout/toolbar_srp" />
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="5dp"
app:tabGravity="fill"
app:tabIndicatorColor="#android:color/white"
app:tabMode="fixed" />
</android.support.design.widget.AppBarLayout>
<!-- All Scrollable Views -->
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
<!-- Bottom bar-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="#a0000000"
android:orientation="horizontal"
android:paddingBottom="#dimen/padding_small"
android:paddingTop="#dimen/padding_small">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.33"
android:gravity="center"
android:paddingBottom="#dimen/padding_small"
android:paddingTop="#dimen/padding_small"
android:text="AC"
android:textColor="#color/white" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.33"
android:gravity="center"
android:paddingBottom="#dimen/padding_small"
android:paddingTop="#dimen/padding_small"
android:text="Sleeper"
android:textColor="#color/white" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.33"
android:gravity="center"
android:paddingBottom="#dimen/padding_small"
android:paddingTop="#dimen/padding_small"
android:text="Premium"
android:textColor="#color/white" />
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
fragment.xml (here I was putted my recyclerview code)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingBottom="#dimen/padding_small"
android:paddingTop="#dimen/padding_small"
android:weightSum="1">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.33"
android:background="#drawable/bg_srp_sorter"
android:clickable="true"
android:gravity="center"
android:paddingBottom="#dimen/padding_small"
android:paddingTop="#dimen/padding_small"
android:text="Departure" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.33"
android:background="#drawable/bg_srp_sorter"
android:gravity="center"
android:paddingBottom="#dimen/padding_small"
android:paddingTop="#dimen/padding_small"
android:text="Duration" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.33"
android:gravity="center"
android:paddingBottom="#dimen/padding_small"
android:paddingTop="#dimen/padding_small"
android:text="Price" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#color/lite_gray"></View>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:weightSum="1">
<android.support.v7.widget.RecyclerView
android:id="#+id/bus_list_recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
</LinearLayout>
toolbar.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"
android:minHeight="?attr/actionBarSize">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:weightSum="1">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.10">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/abc_ic_ab_back_mtrl_am_alpha" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.78"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="1">
<TextView
android:id="#+id/toolbar_title_source"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.47"
android:ellipsize="end"
android:singleLine="true"
android:text="Thiruvananthapuram "
android:textColor="#color/white"
android:textSize="#dimen/label_text_size_large" />
<TextView
android:id="#+id/toolbar_title_arrow"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.08"
android:text="#string/char_right"
android:textColor="#color/white"
android:textSize="#dimen/label_text_size_large"
android:textStyle="bold" />
<TextView
android:id="#+id/toolbar_title_destination"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.47"
android:ellipsize="end"
android:singleLine="true"
android:text=" Cochin"
android:textColor="#color/white"
android:textSize="#dimen/label_text_size_large" />
</LinearLayout>
<TextView
android:id="#+id/toolbar_sub_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="2 Seat(s)"
android:textColor="#color/lite_gray"
android:textSize="#dimen/label_text_size_normal" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.13">
<ImageView
android:layout_width="30dp"
android:layout_height="30dp"
android:scaleType="fitCenter"
android:src="#drawable/filter" />
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.Toolbar>
This how I did it:
mRecylerView.addOnScrollListener(new HideShowScrollListener() {
#Override
public void onHide() {
//fab.animate().setInterpolator(new AccelerateDecelerateInterpolator()).scaleX(0).scaleY(0);
// do your hiding animation here
}
#Override
public void onShow() {
// fab.animate().setInterpolator(new AccelerateDecelerateInterpolator()).scaleX(1).scaleY(1);
// do your showing animation here
}
});
You will be needing HideShowScrollListener.class
/**
* This class is a ScrollListener for RecyclerView that allows to show/hide
* views when list is scrolled.
* */
public abstract class HideShowScrollListener extends RecyclerView.OnScrollListener {
private static final int HIDE_THRESHOLD = 20;
private int scrolledDistance = 0;
private boolean controlsVisible = true;
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (scrolledDistance > HIDE_THRESHOLD && controlsVisible) {
onHide();
controlsVisible = false;
scrolledDistance = 0;
} else if (scrolledDistance < -HIDE_THRESHOLD && !controlsVisible) {
onShow();
controlsVisible = true;
scrolledDistance = 0;
}
if((controlsVisible && dy>0) || (!controlsVisible && dy<0)) {
scrolledDistance += dy;
}
}
public abstract void onHide();
public abstract void onShow();
}
since you are using CoordinatorLayout you could create a custom Behaviour that can achieve what you requested follow example below:
create a class that extends CoordinatorLayout.Behavior<View> follow example below:
public class QuickReturnFloaterBehavior extends CoordinatorLayout.Behavior<View> {
private int distance;
public QuickReturnFloaterBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
}
#Override public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) {
if (dy > 0 && distance < 0 || dy < 0 && distance > 0) {
child.animate().cancel();
distance = 0;
}
distance += dy;
final int height = child.getHeight() > 0 ? (child.getHeight()) : 600/*update this accordingly*/;
if (distance > height && child.isShown()) {
hide(child);
} else if (distance < 0 && !child.isShown()) {
show(child);
}
}
private void hide(View view) {
view.setVisibility(View.GONE);// use animate.translateY(height); instead
}
private void show(View view) {
view.setVisibility(View.VISIBLE);// use animate.translateY(-height); instead
}
}
now to apply this behaviour add this to your layout
app:layout_behavior="com.example.QuickReturnFloaterBehavior"
Visibility and Hide with Animation in Your Fragment:
recyclerView.addOnScrollListener(new HideShowScrollListener() {
final Fragment parentFragment = getParentFragment();
#Override
public void onHide() {
bottomLayout.animate().setDuration(200).translationYBy(-bottomLayout.getHeight()).setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
bottomLayout.setVisibility(View.GONE);
}
});
}
#Override
public void onShow() {
bottomLayout.animate().setDuration(200).translationY(0).setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
bottomLayout.setVisibility(View.VISIBLE);
}
});
}
#Override
public void onScrolled() {
// To load more data
}
});
HideShowScrollListener.java
public abstract class HideShowScrollListener extends RecyclerView.OnScrollListener {
private static final int HIDE_THRESHOLD = 20;
private int scrolledDistance = 0;
private boolean controlsVisible = true;
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
onScrolled();
if (scrolledDistance > HIDE_THRESHOLD && controlsVisible) {
onHide();
controlsVisible = false;
scrolledDistance = 0;
} else if (scrolledDistance < -HIDE_THRESHOLD && !controlsVisible) {
onShow();
controlsVisible = true;
scrolledDistance = 0;
}
if((controlsVisible && dy>0) || (!controlsVisible && dy<0)) {
scrolledDistance += dy;
}
}
public abstract void onHide();
public abstract void onShow();
public abstract void onScrolled();
}
package com.keshav.hideactionbarandfooterexample;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import java.util.ArrayList;
import java.util.List;
import adapters.RecyclerAdapter;
import listners.HidingScrollListener;
public class MainActivity extends AppCompatActivity {
private Toolbar mToolbar;
private Toolbar toolbar_bottom;
private ImageButton mFabButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(R.style.AppThemeRed);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.e("keshav", "MainActivity called");
initToolbar();
mFabButton = (ImageButton) findViewById(R.id.fabButton);
initRecyclerView();
}
private void initToolbar() {
mToolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar_bottom = (Toolbar) findViewById(R.id.toolbar_bottom);
setSupportActionBar(mToolbar);
setSupportActionBar(toolbar_bottom);
setTitle(getString(R.string.app_name));
mToolbar.setTitleTextColor(getResources().getColor(android.R.color.white));
toolbar_bottom.setTitleTextColor(getResources().getColor(android.R.color.white));
toolbar_bottom.setVisibility(View.GONE);
}
private void initRecyclerView() {
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
RecyclerAdapter recyclerAdapter = new RecyclerAdapter(createItemList());
recyclerView.setAdapter(recyclerAdapter);
recyclerView.addOnScrollListener(new HidingScrollListener() {
#Override
public void onHide() {
hideViews();
}
#Override
public void onShow() {
showViews();
}
});
}
private void hideViews() {
// TODO (-mToolbar) plus means 2 view above ho jaye or not visible to user
mToolbar.animate().translationY(-mToolbar.getHeight()).setInterpolator(new AccelerateInterpolator(2));
// TODO uncomment this Hide Footer in android when Scrolling
// TODO (+mToolbar) plus means 2 view forward ho jaye or not visible to user
toolbar_bottom.animate().translationY(+toolbar_bottom.getHeight()).setInterpolator(new AccelerateInterpolator(2));
// TODO keshav Hide Also Floatng Button In Android
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mFabButton.getLayoutParams();
int fabBottomMargin = lp.bottomMargin;
mFabButton.animate().translationY(mFabButton.getHeight() + fabBottomMargin).setInterpolator(new AccelerateInterpolator(2)).start();
// TODO keshav Hide Also Floatng Button In Android
}
private void showViews() {
mToolbar.animate().translationY(0).setInterpolator(new DecelerateInterpolator(2));
// TODO uncomment this Hide Footer in android when Scrolling
toolbar_bottom.animate().translationY(0).setInterpolator(new DecelerateInterpolator(2));
mFabButton.animate().translationY(0).setInterpolator(new DecelerateInterpolator(2)).start();
}
private List<String> createItemList() {
List<String> itemList = new ArrayList<>();
for (int i = 0; i < 20; i++) {
itemList.add("Item " + i);
}
return itemList;
}
}
=============================================
RecyclerAdapter
=============================================
package adapters;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.keshav.hideactionbarandfooterexample.R;
import java.util.List;
/*
* RecyclerView Adapter that allows to add a header view.
* */
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int TYPE_HEADER = 2;
private static final int TYPE_ITEM = 1;
private List<String> mItemList;
public RecyclerAdapter(List<String> itemList) {
mItemList = itemList;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
if (viewType == TYPE_ITEM) {
final View view = LayoutInflater.from(context).inflate(R.layout.recycler_item, parent, false);
return RecyclerItemViewHolder.newInstance(view);
} else if (viewType == TYPE_HEADER) {
final View view = LayoutInflater.from(context).inflate(R.layout.recycler_header, parent, false);
return new RecyclerHeaderViewHolder(view);
}
throw new RuntimeException("There is no type that matches the type " + viewType + " + make sure your using types correctly");
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
if (!isPositionHeader(position)) {
RecyclerItemViewHolder holder = (RecyclerItemViewHolder) viewHolder;
String itemText = mItemList.get(position - 1); // header
holder.setItemText(itemText);
}
}
public int getBasicItemCount() {
return mItemList == null ? 0 : mItemList.size();
}
#Override
public int getItemViewType(int position) {
if (isPositionHeader(position)) {
return TYPE_HEADER;
}
return TYPE_ITEM;
}
#Override
public int getItemCount() {
return getBasicItemCount() + 1; // header
}
private boolean isPositionHeader(int position) {
return position == 0;
}
}
=====================================================
RecyclerHeaderViewHolder
=====================================================
package adapters;
import android.support.v7.widget.RecyclerView;
import android.view.View;
public class RecyclerHeaderViewHolder extends RecyclerView.ViewHolder {
public RecyclerHeaderViewHolder(View itemView) {
super(itemView);
}
}
=====================================================
RecyclerItemViewHolder
=====================================================
package adapters;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.TextView;
import com.keshav.hideactionbarandfooterexample.R;
public class RecyclerItemViewHolder extends RecyclerView.ViewHolder {
private final TextView mItemTextView;
public RecyclerItemViewHolder(final View parent, TextView itemTextView) {
super(parent);
mItemTextView = itemTextView;
}
public static RecyclerItemViewHolder newInstance(View parent) {
TextView itemTextView = (TextView) parent.findViewById(R.id.itemTextView);
return new RecyclerItemViewHolder(parent, itemTextView);
}
public void setItemText(CharSequence text) {
mItemTextView.setText(text);
}
}
===================================================
activity_main.xml
===================================================
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"/>
<ImageButton
android:id="#+id/fabButton"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_gravity="bottom|right"
android:layout_marginBottom="16dp"
android:layout_marginRight="16dp"
android:background="#drawable/fab_bcg"
android:src="#drawable/ic_favorite_outline_white_24dp"
android:contentDescription="#string/fab_description"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar_bottom"
android:layout_width="match_parent"
android:layout_alignParentBottom="true"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"/>
</RelativeLayout>
</FrameLayout>
==================================================
recycle_header.xml in layout folder
==================================================
<?xml version="1.0" encoding="utf-8"?>
<View xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"/>
==================================================
recycle_item.xml in layout folder
==================================================
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="8dp"
card_view:cardCornerRadius="4dp">
<TextView
android:id="#+id/itemTextView"
android:layout_width="match_parent"
android:layout_height="?attr/listPreferredItemHeight"
android:gravity="center_vertical"
android:padding="8dp"
style="#style/Base.TextAppearance.AppCompat.Body2"/>
</android.support.v7.widget.CardView>
=================================================
styles.xml
=================================================
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
</style>
<style name="AppThemeRed" parent="AppTheme">
<item name="colorPrimary">#color/color_primary_red</item>
<item name="colorPrimaryDark">#color/color_primary_red_dark</item>
</style>
<style name="AppThemeGreen" parent="AppTheme">
<item name="colorPrimary">#color/color_primary_green</item>
<item name="colorPrimaryDark">#color/color_primary_green_dark</item>
</style>
<style name="AppThemeBlue" parent="AppTheme">
<item name="colorPrimary">#color/color_primary_blue</item>
<item name="colorPrimaryDark">#color/color_primary_blue_dark</item>
<item name="colorAccent">#color/color_accent_pink</item>
</style>
</resources>
build.gradle Dependency
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support:recyclerview-v7:25.3.1'
compile 'com.android.support:cardview-v7:25.3.1'
compile 'com.android.support:design:25.3.1'
#k0sh gave a fine solution. I want to update it to get a smooth animation
while showing and hiding the layout. Replace complete code inside
onNestedPreScroll() with the below code:
if (dy > 0) {
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) child.getLayoutParams();
int viewBottomMargin = layoutParams.bottomMargin;
child.animate().translationY(child.getHeight() + viewBottomMargin).setInterpolator(new LinearInterpolator()).start();
} else if (dy < 0) {
child.animate().translationY(0).setInterpolator(new LinearInterpolator()).start();
}
#k0sh's QuickReturnFloaterBehavior works but it sometimes not listen to the slight scrolls.
I am having contents in NestedScrollView with a LinearLayout as a bottom bar & didn't have the recycler view. so, I can't use other suggested answers.
Those who are having the same situation can use the BottomNavigationBehavior from this post Bottom Navigation Behavior. it works perfectly & useful.
When the current top-level view has a scrolling content, the bottom
navigation should hide when it is scrolled down and retract back when
the content is scrolled up. For this purpose, we need to be aware of
the direction of the scroll. VerticalScrollingBehavior is a generic
layout behavior that it is somehow an extension to the
CoordinatorLayout.Behavior that dispatches events on for direction of
scrolling.
source code for BottomNavigationBehavior - https://gist.github.com/NikolaDespotoski/1d6fef4949eb9be05a46#file-bottomnavigationbehavior-java
snippet from BottomNavigationBehavior
#Override
public void onDirectionNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx, int dy, int[] consumed, #ScrollDirection int scrollDirection) {
handleDirection(child, scrollDirection);
}
#Override
protected boolean onNestedDirectionFling(CoordinatorLayout coordinatorLayout, V child, View target, float velocityX, float velocityY, #ScrollDirection int scrollDirection) {
handleDirection(child, scrollDirection);
return true;
}
private void handleDirection(V child, #ScrollDirection int scrollDirection) {
if (!scrollingEnabled) return;
if (scrollDirection == ScrollDirection.SCROLL_DIRECTION_DOWN && hidden) {
hidden = false;
animateOffset(child, 0);
} else if (scrollDirection == ScrollDirection.SCROLL_DIRECTION_UP && !hidden) {
hidden = true;
animateOffset(child, child.getHeight());
}
}

How to sync scroll of two CoordinatorLayout + AppBarLayout

I have an activity with XML.
Something like:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.support.design.widget.CoordinatorLayout
android:id="#+id/coordinator"
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="#color/primary"
android:theme="#style/ToolbarStyle"
android:gravity="center_vertical"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
app:layout_scrollFlags="scroll|enterAlways|snap"
style="#style/bold" />
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/TabLayoutStyle"
android:animateLayoutChanges="true"
app:tabGravity="fill"
app:tabMode="fixed"
app:tabTextAppearance="#style/TabStyle"/>
</android.support.design.widget.AppBarLayout>
<com.wedmegood.planner.view.XViewPager
android:id="#+id/main_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="fill_vertical"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
...
</android.support.v4.widget.DrawerLayout>
A Fragment of the ViewPager has a CoordinatorLayout and AppBarLayout + CollapsingToolbarLayout.
Fragment's XML:
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/primaryDark"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/collapse_toolbar"
android:layout_width="match_parent"
android:layout_height="#dimen/my_wedding_banner_height"
android:minHeight="48dp"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<RelativeLayout
android:id="#+id/banner"
android:layout_width="match_parent"
android:layout_marginTop="0dp"
android:layout_height="match_parent"
app:layout_collapseMode="none">
</RelativeLayout>
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_gravity="bottom"
android:animateLayoutChanges="true"
app:tabMode="fixed"
app:tabGravity="fill"
app:tabTextColor="#color/primary"
app:tabSelectedTextColor="#color/primary"
app:tabIndicatorColor="#color/accent"
app:tabIndicatorHeight="4dp"
app:tabTextAppearance="#style/TabStyle"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<com.wedmegood.planner.view.XViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>
The fragment has a banner, the RelativeLayout. I want to sync scroll of these two AppBarLayouts so that the outer AppBar collapses either before/after (doesn't matter if it happens before or after) the inside AppBar collapses? I tried setting and unsetting scroll flags of 2 AppBars depending on their Offset change listener, it kinda works but doesn't give a smooth scroll effect. I can change the fragment's XML completely as long as the banner works fine.
Also, is there a way to change style / call TabLayout's setTabTextColors when CollapsingToolbarLayout collapses/expands?
I face the same problem days ago. Finally, I found a solution from SwipeRefreshLayout. Just extend CoordinatorLayout and implement NestedScrollingChild interface. It works!
here is my code:
public class NestedCoordinatorLayout extends CoordinatorLayout implements NestedScrollingChild {
private final NestedScrollingChildHelper mNestedScrollingChildHelper;
private final int[] mParentOffsetInWindow = new int[2];
private final int[] mParentScrollConsumed = new int[2];
public NestedCoordinatorLayout(Context context) {
this(context, null, 0);
}
public NestedCoordinatorLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public NestedCoordinatorLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mNestedScrollingChildHelper = new NestedScrollingChildHelper(this);
setNestedScrollingEnabled(true);
}
// NestedScrollingChild
#Override
public void setNestedScrollingEnabled(boolean enabled) {
mNestedScrollingChildHelper.setNestedScrollingEnabled(enabled);
}
#Override
public boolean isNestedScrollingEnabled() {
return mNestedScrollingChildHelper.isNestedScrollingEnabled();
}
#Override
public boolean startNestedScroll(int axes) {
return mNestedScrollingChildHelper.startNestedScroll(axes);
}
#Override
public void stopNestedScroll() {
mNestedScrollingChildHelper.stopNestedScroll();
}
#Override
public boolean hasNestedScrollingParent() {
return mNestedScrollingChildHelper.hasNestedScrollingParent();
}
#Override
public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed,
int dyUnconsumed, int[] offsetInWindow) {
return mNestedScrollingChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed,
dxUnconsumed, dyUnconsumed, offsetInWindow);
}
#Override
public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
return mNestedScrollingChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
}
#Override
public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
return mNestedScrollingChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
}
#Override
public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
return mNestedScrollingChildHelper.dispatchNestedPreFling(velocityX, velocityY);
}
#Override
public void onNestedScrollAccepted(View child, View target, int axes) {
super.onNestedScrollAccepted(child, target, axes);
// Dispatch up to the nested parent
startNestedScroll(axes & ViewCompat.SCROLL_AXIS_VERTICAL);
}
#Override
public void onStopNestedScroll(View target) {
super.onStopNestedScroll(target);
stopNestedScroll();
}
#Override
public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
super.onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
mParentOffsetInWindow);
}
#Override
public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
super.onNestedPreScroll(target, dx, dy, consumed);
final int[] parentConsumed = mParentScrollConsumed;
if (dispatchNestedPreScroll(dx - consumed[0], dy - consumed[1], parentConsumed, null)) {
consumed[0] += parentConsumed[0];
consumed[1] += parentConsumed[1];
}
}
}
Use it in your fragment's layout (Inner coordinator layout).
How can I sync scroll of these 2 AppBarLayouts so that the outer
appbar collapses either before/after (doesn't matter if it happens
before or after) the inside appbar collapses?
Delete that Fragment's CoordinatorLayout and just use RelativeLayout as a root tag (for Fragment)and then do your stuffs with that ViewPager in the MainActivity.
For example, use it inside that CoordinatorLayout like this:
<CoordinatorLayout>
<android.support.v4.view.ViewPager/>
<AppbarLayout/>
<scrollableView/>
<FloatingActionButton/>
</CoordinatorLayout>
Github example:
https://github.com/TheLittleNaruto/SupportDesignExample
Or perhaps you want to scroll that ViewPager inside the NestedScrollView but, you'll face a problem then use the following code inside it:
app:layout_behavior="#string/appbar_scrolling_view_behavior"
That's pretty much it.
A fragment of the ViewPager has a CoordinatorLayout and
AppBarLayout+CollapsingToolbarLayout. XML:
You don't need to use them twice.

Categories

Resources