h8MyJob
h8MyJob

Reputation: 183

CollapsingToolBarLayout Animation Stops

Is there a way to disable the interruption of the animation of a CollapsingToolBarLayout ?

We have a collapsing tool bar with an image that we are programmatically collapsing with animation by calling method app_bar.setExpanded(false, true) on the enclosing AppBarLayout object. This is done by attaching an onClickListener on a button that triggers the setExpanded(false,true) method .

The problem we are encountering is that the animation gets interrupted if we tap the screen more than once fast enough. The taps can be on the triggering button, which is wrapped in a debouncer; or on the button once and anywhere on the screen for the additional times. When that happens, the image view gets stuck, the tool bar doesn't collapse, and it is not possible to manually complete the animation. The back button needs to be pressed to bring the view to the its original state.

Below is an except of the layout:

<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/app_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:elevation="@dimen/rc_tab_elevation">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_scrollFlags="scroll">

            <FrameLayout
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:orientation="vertical">

                <TextView
                    android:id="@+id/image_placeholder_text"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"/>

                <ImageView
                    android:id="@+id/image_pic"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_gravity="center"
                    android:clickable="false"/>
            </FrameLayout>
        </android.support.design.widget.CollapsingToolbarLayout>

        <android.support.design.widget.CollapsingToolbarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <android.support.design.widget.TabLayout
                android:id="@+id/tab_layout"
                style="@style/Tabs"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:tabMode="scrollable"/>
        </android.support.design.widget.CollapsingToolbarLayout>
    </android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>

The excerpt code for the listener called in a fragment.java subclass:

app_bar.setExpanded(expanded, true);
tab_layout.setVisibility(View.GONE);

Any help, tips, or hints are welcome.

Thank you in advance.

Upvotes: 0

Views: 817

Answers (1)

h8MyJob
h8MyJob

Reputation: 183

I was able to work something out and i'm posting the solution here. Hopefully, it'll be of use to someone.

The root of the problem is the nature of CollapsingToolBarLayout widget that always responds to touch events. Therefore, the solution consists of ignoring touch events once the collapsing animation is triggered.

  1. Below is the method that collapses the toolbar and a boolean instance variable, collapseTriggered, is created in order hold the state that a collapse is triggered.

    public void collapseToolBar(){ 
        collapseTriggered = true; 
        app_bar.setExpanded(expanded, true); 
        tab_layout.setVisibility(View.GONE); 
    }
    
  2. Override the touch event listener in the activity. This is crucial so that the animation doesn't get interrupted mid execution in case of a touch event.The method in question is dispatchTouchEvent(MovtionEvent).

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if( collapseTriggered == true){
           return true;     //if collapsed is triggered ignore all touch events
        }
        return super.disptachTouchEvent(ev); //otherwise, dispatch as usual
    }
    
  3. Once collapse animation is done, change collapseTriggered variable to false. This is needed so that regular processing of touch events can resume after collapse animation is done -- in other words, once toolbar is fully collapsed. To do so, an onOffSetListener() was added to the toolbar and detects when toolbard is fully collpased.

     private void addFullyCollapsedListener() {
        app_bar.addOnOffSetChangedListener(
            new AppBarLayout.OnOffsetChangedListener() {
            @Override
            public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
                if (Math.abs(verticalOffset) == appBarLayout.getTotalScrollRange()) {
                showMapSelected = false;
                }
            }
     });
    
  4. Watch Out For Remember to account for odd scenarios in which collapseTriggered doesn't get set to false after being set to true. In such cases, touch events can ignored and this can potentially signal to the user that the app has frozen. In my case, collapsedTriggered gets set to false as part of the onResume() method.

Upvotes: 1

Related Questions