Search code examples
androidandroid-coordinatorlayoutandroid-collapsingtoolbarlayoutandroid-appbarlayoutcoordinator-layout

How do I make a Scrollable TextView inside CollapsingToolbar?


I am currently experimenting with CoordinatorLayout + AppbarLayout + CollapsingToolbarLayout in a way such that:

1) Scroll down the Appbar using "Toolbar" [ No Nested ScrollView / RecyclerView ].

2) The content below the appbar should move along with the appbar scrolling.

3) Multiple images kept under ViewPager.

4) The last item in the ViewPager would be an textview.

I have achieved 1) and 2) using the following 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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:tools="http://schemas.android.com/tools">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/flexible.example.appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        >

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/flexible.example.collapsing"
            android:layout_width="match_parent"
            android:layout_height="300dp"
            app:expandedTitleMarginBottom="94dp"
            app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
            app:contentScrim="?colorPrimary"
            >

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_margin="10dp"
                android:id="@+id/text_sample"
                android:scrollbars="vertical"
                android:scrollIndicators="right"
                app:layout_collapseMode="parallax"
                app:layout_scrollFlags="scroll|enterAlways"
                android:layout_gravity="center"
                android:nestedScrollingEnabled="true"
                />
        </android.support.design.widget.CollapsingToolbarLayout>

        <android.support.v7.widget.Toolbar
            android:id="@+id/ioexample.toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="@color/PM01"
            android:elevation="4dp"
            app:layout_collapseMode="pin"
            app:layout_anchor="@id/flexible.example.collapsing"
            app:layout_anchorGravity="bottom"
            app:theme="@style/ThemeOverlay.AppCompat.Light"
            style="@style/ToolBarWithNavigationBack"
            app:layout_scrollFlags="scroll|enterAlways|snap"
            >

        </android.support.v7.widget.Toolbar>


    </android.support.design.widget.AppBarLayout>

    <android.support.v7.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/recyclerviewcontainer"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

</android.support.design.widget.CoordinatorLayout>

What I am trying to achieve now is to make the textview inside collpasingtoolbarlayout is to be scrollable (#4 above). Since my search till now has made me believe that the Appbar is handling all the touch events by itself, this doesn't seems to be easy. But since it is a requirement, I would be more than happy to have a guidance / pointers to help me complete this.

Can someone please let me know what and where to look for achieving this functionality.


Solution

  • After a lot of research and some more searching through SO, I got an idea what I need to do in order to achieve the desired effect:

    1) Implement a custom behavior for appbarlayout :

    public class AppBarLayoutCustomBehavior extends AppBarLayout.Behavior {
        private boolean setIntercept = false;
        private boolean lockAppBar = false;
    
        DragCallback mDragCallback = new DragCallback() {
            @Override
            public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
                return !lockAppBar;
            }
        };
    
        @Override
        public boolean onInterceptTouchEvent(CoordinatorLayout parent, AppBarLayout child, MotionEvent ev) {
            super.onInterceptTouchEvent(parent, child, ev);
            return setIntercept;
        }
    
        public void setInterceptTouchEvent(boolean set) {
            setIntercept = set;
        }
    
        public AppBarLayoutCustomBehavior() {
            super();
            setDragCallback(mDragCallback);
        }
    
        public AppBarLayoutCustomBehavior(Context ctx, AttributeSet attributeSet) {
            super(ctx, attributeSet);
            setDragCallback(mDragCallback);
        }
    
        public void lockAppBar() {
            lockAppBar = true;
        }
    
        public void unlockAppBar() {
            lockAppBar = false;
        }
    }
    

    2) Use this custom behavior with app bar :

    CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams)appBarLayout.getLayoutParams();
            final AppBarLayoutCustomBehavior mBehavior = new AppBarLayoutCustomBehavior();
            lp.setBehavior(mBehavior);
    
    /// use toolbar to enable/disable dragging on the appbar behavior. This way
    /// out toolbar acts as a drag handle for the app bar.
            Toolbar toolbar = (Toolbar) activity.findViewById(R.id.main_toolbar);
            toolbar.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    switch(event.getAction()) {
                        case MotionEvent.ACTION_DOWN:
                            mBehavior.setInterceptTouchEvent(true);
                            return true;
                        case MotionEvent.ACTION_CANCEL:
                            mBehavior.setInterceptTouchEvent(false);
                            return true;
                    }
                    return false;
                }
            });
    

    3) Set movement method on the textview to make it scrollable

    textView.setMovementMethod(ScrollingMovementMethod.getInstance());