How to collapse/expand a view based on scroll direction?

前端 未结 4 1836
一整个雨季
一整个雨季 2020-12-11 04:39

I have a View and a RecyclerView housed in a LinearLayout. What I want to achieve is something like this:

https://material.google.com/patterns/scrolling-techniques.h

相关标签:
4条回答
  • 2020-12-11 04:40

    You have to use Coordinator Layout with the 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: the comments will give errors if you put on a xml file. Is on propose so you will remember to read hahahah

    0 讨论(0)
  • 2020-12-11 04:46

    To achieve toolbar to expand and collapse smoothly you can apply translate animation or use CoordinatorLayout with AppBarLayout and Toolbar.

    Animation : First you have to detect scroll up and scroll down on your RecyclerView. To do so you can set “setOnScrollListener” on your RecyclerView. Once you have both scroll up and scroll down, simply apply animation.

    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;
                            }
                        });
            }
        }
    

    CoordinatorLayout with AppBarLayout and Toolbar: By using coordinatorLayout with appBarLayout and toolbar, and set the scroll flag used within the attribute app:layout_scrollFlags to achieve the scroll effect. It must be enabled for any scroll effects to take into effect. This flag must be enabled along with enterAlways, enterAlwaysCollapsed, exitUntilCollapsed, or snap.

    • enterAlways: The view will become visible when scrolling up. This flag is useful in cases when scrolling from the bottom of a list and wanting to expose the Toolbar as soon as scrolling up takes place.
    • enterAlwaysCollapsed: Normally, when only enterAlways is used, the Toolbar will continue to expand as you scroll down.Assuming enterAlways is declared and you have specified a minHeight, you can also specify enterAlwaysCollapsed. When this setting is used, your view will only appear at this minimum height. Only when scrolling reaches to the top will the view expand to its full height
    • exitUntilCollapsed: When the scroll flag is set, scrolling down will normally cause the entire content to move.By specifying a minHeight and exitUntilCollapsed, the minimum height of the Toolbar will be reached before the rest of the content begins to scroll and exit from the screen
    • snap: Using this option will determine what to do when a view only has been partially reduced. If scrolling ends and the view size has been reduced to less than 50% of its original, then this view to return to its original size. If the size is greater than 50% of its sized, it will disappear completely.

    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>
    
    0 讨论(0)
  • 2020-12-11 04:51

    Try this:- I also want this kind of animation on custom view and i have 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);
                    scrolledDistance = dy;
                    if (scrolledDistance > HIDE_THRESHOLD && controlsVisible) {
                        hideViews();
                        controlsVisible = false;
                    } else if (scrolledDistance < -HIDE_THRESHOLD && !controlsVisible) {
                        showViews();
                        controlsVisible = true;
                    }
                }
            });
        }
    
        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 this 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 it also helps you...

    0 讨论(0)
  • 2020-12-11 05:03

    You need to use CoordinatorLayout to achieve what you want. You could find all needed information in this tutorial.

    0 讨论(0)
提交回复
热议问题