How to collapse / expand the view depending on the direction of scrolling?

I have View and RecyclerView hosted in LinearLayout. I want to achieve something like this:

https://material.google.com/patterns/scrolling-techniques.html#scrolling-techniques-behavior

Basically, when I view the RecyclerView, the view is minimized. It expands as I scroll down the RecyclerView.

I tried various methods, but the animation stutters if the finger twitches around the scroll position. It animates well if the finger makes an intentional scroll motion in one direction. How to do it right?

+6
source share
4 answers

You must use the coordinator layout using CollapsingToolbarLayout

<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:clipToPadding="false"> <android.support.design.widget.AppBarLayout android:id="@+id/app_bar_layout" android:layout_width="match_parent" android:layout_height="210dp" android:stateListAnimator="@animator/appbar_always_elevated" //I put this here because I want to have shadow when is open, but you have to create the xml file. android:background="@color/WHITE"> <android.support.design.widget.CollapsingToolbarLayout android:id="@+id/collapsing_toolbar_layout" android:layout_width="match_parent" android:layout_height="match_parent" app:collapsedTitleTextAppearance="@style/TextAppearance.AppCompat.Widget.ActionBar.Title.Inverse" app:expandedTitleMarginStart="72dp" app:expandedTitleTextAppearance="@style/TextAppearance.AppCompat.Widget.ActionBar.Title.Inverse" app:layout_scrollFlags="scroll|exitUntilCollapsed"> //HERE you should take a look what you want your collapse bar do. <Here you put the content for you collapse bar, like a ImageView> <android.support.v7.widget.Toolbar //This is the size of your fixed bar when you collapse, even here you can put a back button, for example android:id="@+id/app_bar" android:layout_width="match_parent" android:layout_height="40dp" app:layout_collapseMode="pin" /> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout> <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/main_home_list_swipe" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" > <android.support.v7.widget.RecyclerView android:id="@+id/main_home_list" android:layout_width="match_parent" android:layout_height="match_parent"/> </android.support.design.widget.CoordinatorLayout > 

Obs: comments will give errors if you put in an xml file. It is suggested that you do not forget to read hahahah

+3
source

To make the toolbar expand and smooth smoothly, you can apply translation animations or use CoordinatorLayout using the AppBarLayout and toolbar.

Animation: First you have to detect a scroll up and scroll down your RecyclerView. To do this, you can set "setOnScrollListener" in the RecyclerView. When you have scroll up and scroll down, just apply the animation.

The code:

 rvHomeList.setOnScrollListener(new RecyclerView.OnScrollListener() { int verticalOffset; boolean scrollingUp; @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { if (newState == RecyclerView.SCROLL_STATE_IDLE) { if (scrollingUp) { Log.e("onScrollStateChanged", "UP"); if (verticalOffset > llTop.getHeight()) { toolbarAnimateHide(); } } else { Log.e("onScrollStateChanged", "down"); if (llTop.getTranslationY() < llTop.getHeight() * -0.6 && verticalOffset > llTop.getHeight()) { toolbarAnimateHide(); } else { toolbarAnimateShow(verticalOffset); } } } } @Override public final void onScrolled(RecyclerView recyclerView, int dx, int dy) { verticalOffset += dy; scrollingUp = dy > 0; int toolbarYOffset = (int) (dy - llTop.getTranslationY()); llTop.animate().cancel(); if (scrollingUp) { Log.e("onScrolled", "UP"); if (toolbarYOffset < llTop.getHeight()) { llTop.setTranslationY(-toolbarYOffset); } else { llTop.setTranslationY(-llTop.getHeight()); } } else { Log.e("onScrolled", "down"); if (toolbarYOffset < 0) { llTop.setTranslationY(0); } else { llTop.setTranslationY(-toolbarYOffset); } } } }); 

Animation Methods:

 private void toolbarAnimateShow(final int verticalOffset) { if (!isShowing) { isShowing = true; llTop.animate() .translationY(0) .setInterpolator(new LinearInterpolator()) .setDuration(180) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { llTop.setVisibility(View.VISIBLE); isShowing = false; } }); } } private void toolbarAnimateHide() { if (!isHidding) { isHidding = true; llTop.animate() .translationY(-llTop.getHeight()) .setInterpolator(new LinearInterpolator()) .setDuration(180) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { llTop.setVisibility(View.GONE); isHidding = false; } }); } } 

Coordinator Layout with AppBarLayout and toolbar:. Using the Layout coordinator using appBarLayout and the toolbar and set the scroll flag used in the attribute application: layout_scrollFlags to achieve the scroll effect. It must be enabled for any scroll effects that will work. This flag must be enabled along with enterAlways, enterAlwaysCollapsed, exitUntilCollapsed, or a snap-in.

  • enterAlways: The view will be displayed as you scroll up. This flag is useful when scrolling from the bottom of the list and you want to open the toolbar as soon as it scrolls.
  • enterAlwaysCollapsed: Normally, when only enterAlways is used, the toolbar continues to expand as it scrolls down. The enterAlways declaration is declared, and you specified minHeight, you can also specify enterAlwaysCollapsed. When this option is used, your view will only be displayed at that minimum height. Only when the scroll reaches the top does the view expand to its full height.
  • exitUntilCollapsed: When the scroll flag is set, scrolling down usually will move all content. By specifying minHeight and exitUntilCollapsed, the minimum height of the toolbar will be reached until the rest of the content starts to scroll and exit the screen.
  • binding:. Using this option determines what to do if the view is only partially reduced. If the scroll ends and the size of the view is reduced to less than 50% of its original, then this view will revert to its original size. If the size exceeds 50% of its size, it will completely disappear.

The code:

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/llBase" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/white" android:orientation="vertical"> <android.support.design.widget.CoordinatorLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"> <android.support.design.widget.AppBarLayout android:id="@+id/appbarContainer" 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="@dimen/_40sdp" android:gravity="center" android:theme="@style/ThemeOverlay.AppCompat.Light" app:layout_scrollFlags="scroll|enterAlways"> <include layout="@layout/top_bar" android:layout_width="match_parent" android:layout_height="wrap_content" /> </android.support.v7.widget.Toolbar> </android.support.design.widget.AppBarLayout> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <RelativeLayout android:id="@+id/rlMain" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1"/> </RelativeLayout> </android.support.design.widget.CoordinatorLayout> </LinearLayout> 
+1
source

Try the following: - I also want this animation on a user view, and I achieved it this way.

 public class TestActivity extends AppCompatActivity { private static final int HIDE_THRESHOLD = 20; //this is you custom layout it is any thing. LinearLayout customLayout; private int scrolledDistance = 0; private boolean controlsVisible = true; private RecyclerView recyclerView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.your_layout); recyclerView = (RecyclerView) findViewById(R.id.recyclerView); recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); if (scrolledDistance > HIDE_THRESHOLD && controlsVisible) { hideViews(); controlsVisible = false; scrolledDistance = 0; } else if (scrolledDistance < -HIDE_THRESHOLD && !controlsVisible) { showViews(); controlsVisible = true; scrolledDistance = 0; } } }); } private void hideViews() { customLayout.animate().translationY(-customLayout.getHeight()).setInterpolator(new AccelerateInterpolator(2)); } private void showViews() { customLayout.animate().translationY(0).setInterpolator(new DecelerateInterpolator(2)); } } 

Edit - 1 for ScrollView try listener

 scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() { @Override public void onScrollChanged() { if (scrolledDistance > HIDE_THRESHOLD && controlsVisible) { hideViews(); controlsVisible = false; scrolledDistance = 0; } else if (scrolledDistance < -HIDE_THRESHOLD && !controlsVisible) { showViews(); controlsVisible = true; scrolledDistance = 0; } } }); 

Hope this also helps you ...

+1
source

To achieve the desired result, you must use CoordinatorLayout . You can find all the necessary information in this tutorial .

0
source

All Articles