How to disable NestedScrollView & CollapsingToolbarLayout scrolling, for example, when there is no more content?

Background

I am trying to add the same features as in many applications where the top of the screen is compressed and expanded to fit the scroll content.

For this, I use the Google Design Library, as shown in the CheeseSquare sample .

Problem

The thing is, no matter how much content is in the NestedScrollView, it allows you to scroll down below the last view of the content, just so that I can see the final state of the action bar with a minimum size.

In short, this is what I see when scrolling down (the modified contents of the CheeseSquare sample):

enter image description here

although this is what I would like to have when scrolling down (taken from the contact application):

enter image description here

I am also trying to fix an error in ThreePhasesBottomSheet that allows me to scroll the contents of the bottom sheet even when it is in peek state. To play, start scrolling horizontally (which does nothing, since there is no way to scroll), and then vertically, which somehow will scroll the contents of the bottom sheet.

Therefore, I need to disable scrolling in the transformView () method, in case "translation

Here's how it works using normal use:

enter image description here

And this is how it behaves with the error of not blocking scrolling:

enter image description here

What i tried

I tried playing with the layout_scrollFlags flags to change the height to wrap_content and to remove the clipToPadding and fitsSystemWindows attributes.

Here is an example XML file that I modified to include only one cardView instead of many:

<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/main_content" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true"> <android.support.design.widget.AppBarLayout android:id="@+id/appbar" android:layout_width="match_parent" android:layout_height="@dimen/detail_backdrop_height" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" android:fitsSystemWindows="true"> <android.support.design.widget.CollapsingToolbarLayout android:id="@+id/collapsing_toolbar" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_scrollFlags="scroll|exitUntilCollapsed" android:fitsSystemWindows="true" app:contentScrim="?attr/colorPrimary" app:expandedTitleMarginStart="48dp" app:expandedTitleMarginEnd="64dp"> <ImageView android:id="@+id/backdrop" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" android:fitsSystemWindows="true" app:layout_collapseMode="parallax" /> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" app:layout_collapseMode="pin" /> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout> <android.support.v4.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingTop="24dp"> <android.support.v7.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="@dimen/card_margin"> <LinearLayout style="@style/Widget.CardContent" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Info" android:textAppearance="@style/TextAppearance.AppCompat.Title" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/cheese_ipsum" /> </LinearLayout> </android.support.v7.widget.CardView> </LinearLayout> </android.support.v4.widget.NestedScrollView> <android.support.design.widget.FloatingActionButton android:layout_height="wrap_content" android:layout_width="wrap_content" app:layout_anchor="@id/appbar" app:layout_anchorGravity="bottom|right|end" android:src="@drawable/ic_discuss" android:layout_margin="@dimen/fab_margin" android:clickable="true"/> </android.support.design.widget.CoordinatorLayout> 

I also tried the following code:

 ((AppBarLayout.LayoutParams) collapsingToolbar.getLayoutParams()).setScrollFlags(0); 

but it still allowed scrolling of the NestedScrollView itself in the CheeseSquare example, and was also allowed to go to ThreePhasesBottomSheet .

Questions

  • What can I do to stop scrolling when there is no more content to show below?

  • Also, what can be done to disable NestedScrollView scrolling at any time (for ThreePhasesBottomSheet )? Something like "setEnableScrolling (...)"?

    I tried to extend NestedScrollView, and also extend from ScrollingViewBehavior, but could not find what can be done to disable scrolling.

This may be a very simple thing, but I cannot understand that ...

EDIT: if necessary, this is what I am currently using for the design and support library

 compile 'com.android.support:appcompat-v7:23.1.0' compile 'com.android.support:design:23.1.0' 



EDIT: for # 2, I found a workaround from the BottomSheetLayout.java file to disable everything related to the "sheetViewOwnsTouch" variable, as if it was always set to "false". This will allow the theft of touch events on the bottom sheet. However, this is just a workaround, and only for this case. It also raises some touch events that should have been handled by other views. I still want to know how to program scrolling programmatically, as well as in another case with enough space-for-show content.

+60
android material-design android-design-library collapsingtoolbarlayout
Nov 10 '15 at 13:30
source share
2 answers

What can I do to stop scrolling when there is no more content to show below?

Firstly, as I said below, the scroll that you indicated in your question does not apply to NestedScrollView . It belongs to CollapsingToolbarLayout . The NestedScrollView scroll event occurs only when the CollapsingToolbarLayout completely collapses, and, of course, it stops scrolling when there is no more content in it (the bottom is reached). For CollapsingToolbarLayout it will crash to the layout_height toolbar (as in the xml file, you will find "?attr/actionBarSize" ). The following image will demonstrate that pay attention to the red rectangle, which is the toolbar (I set its background)

Image BNK

So, in order to have a solution for your # 1, you need to calculate the height of the NestedScrollView , and then if it is less than the height of the screen, we will fix the height of the toolbar.

In short, you can update activity_detail.xml as follows:

 <?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:id="@+id/main_content" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true"> <android.support.design.widget.AppBarLayout android:id="@+id/appbar" android:layout_width="match_parent" android:layout_height="@dimen/detail_backdrop_height" android:fitsSystemWindows="true" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> <android.support.design.widget.CollapsingToolbarLayout android:id="@+id/collapsing_toolbar" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" app:contentScrim="?attr/colorPrimary" app:layout_scrollFlags="scroll|exitUntilCollapsed"> <ImageView android:id="@+id/backdrop" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="false" android:scaleType="centerCrop" app:layout_collapseMode="parallax" /> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:layout_collapseMode="pin" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" /> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout> <android.support.v4.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <LinearLayout android:id="@+id/linearLayout1" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <android.support.v7.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="@dimen/card_margin"> <LinearLayout style="@style/Widget.CardContent" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Info" android:textAppearance="@style/TextAppearance.AppCompat.Title" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/cheese_ipsum" /> </LinearLayout> </android.support.v7.widget.CardView> </LinearLayout> </android.support.v4.widget.NestedScrollView> </android.support.design.widget.CoordinatorLayout> 

And CheeseDetailActivity.java:

 public class CheeseDetailActivity extends AppCompatActivity { public static final String EXTRA_NAME = "cheese_name"; private final Context mContext = this; private int screenHeight; private int linearLayoutHeight; private int toolbarHeight_org; private int toolbarHeight; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_detail); Intent intent = getIntent(); final String cheeseName = intent.getStringExtra(EXTRA_NAME); screenHeight = getScreenHeight(this); TypedValue typedValue = new TypedValue(); getTheme().resolveAttribute(R.attr.colorPrimary, typedValue, true); final int colorPrimary = typedValue.data; final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); getSupportActionBar().setDisplayHomeAsUpEnabled(true); AppBarLayout appbar = (AppBarLayout) findViewById(R.id.appbar); final CoordinatorLayout.LayoutParams appbarLayoutParams = (CoordinatorLayout.LayoutParams)appbar.getLayoutParams(); final ViewGroup.LayoutParams toolbarLayoutParams = toolbar.getLayoutParams(); if (toolbarLayoutParams != null) { toolbarHeight_org = toolbarLayoutParams.height; toolbarHeight = toolbarLayoutParams.height; } final CollapsingToolbarLayout collapsingToolbar = (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar); collapsingToolbar.setTitle(cheeseName); collapsingToolbar.setContentScrimColor(colorPrimary); collapsingToolbar.setExpandedTitleTextAppearance(R.style.ExpandedTitleTextAppearance); //collapsingToolbar.setCollapsedTitleTextAppearance(R.style.CollapsedTitleTextAppearance); final LinearLayout linearLayout = (LinearLayout) findViewById(R.id.linearLayout1); ViewTreeObserver observer = linearLayout.getViewTreeObserver(); observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { linearLayoutHeight = linearLayout.getHeight(); if (linearLayoutHeight + toolbarHeight < screenHeight) { if (toolbarLayoutParams != null) { toolbarLayoutParams.height = screenHeight - linearLayoutHeight - 20; if (toolbarLayoutParams.height < toolbarHeight_org) { toolbarLayoutParams.height = toolbarHeight_org; } int extended_text_size = (int) getResources().getDimension(R.dimen.expanded_text_size); if (appbarLayoutParams.height - toolbarLayoutParams.height <= extended_text_size) { int value = appbarLayoutParams.height - toolbarLayoutParams.height; if (value < 0) { appbarLayoutParams.height = toolbarLayoutParams.height - value + extended_text_size * 3; } else { appbarLayoutParams.height = toolbarLayoutParams.height + extended_text_size * 3; } if (appbarLayoutParams.height >= screenHeight) { appbarLayoutParams.height = screenHeight; } } // collapsingToolbar.setContentScrimColor(getResources().getColor(android.R.color.transparent)); if (toolbarLayoutParams.height > toolbarHeight_org) { collapsingToolbar.setContentScrimColor(ContextCompat.getColor(mContext, android.R.color.transparent)); } } } // Removes the listener if possible ViewTreeObserver viewTreeObserver = linearLayout.getViewTreeObserver(); if (viewTreeObserver.isAlive()) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { linearLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this); } else { linearLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this); } } } }); loadBackdrop(); appbar.setExpanded(true); } private int getScreenHeight(Context context) { int measuredHeight; Point size = new Point(); WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) { wm.getDefaultDisplay().getSize(size); measuredHeight = size.y; } else { Display d = wm.getDefaultDisplay(); measuredHeight = d.getHeight(); } return measuredHeight; } private void loadBackdrop() { final ImageView imageView = (ImageView) findViewById(R.id.backdrop); Glide.with(this).load(Cheeses.getRandomCheeseDrawable()).centerCrop().into(imageView); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.sample_actions, menu); return true; } } 

Here is the result:

BNK screenshot

With a Cheesesquare sample , I set up this project and uploaded it to My GitHub . I agree that he still has some problems, however, at least this may be the solution to your first problem.

Please take a look. Hope this helps!

+11
Dec 24 '15 at 9:10
source share

To disable scrolling, just set both NestedScrollView and its child LinearLayout height to 'wrap_content'.

This will not work as you wish, but at least it will not scroll if the content is fully fit on the screen.


Speaking of the example of your Contacts application, it looks like it is not using CoordinatorLayout and other things that come with it.

This can be done as follows:

 <ScrollView android:id="@+id/scroll_adinfo" android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <ImageView android:id="@+id/image" android:layout_width="match_parent" android:layout_height="@dimen/image_height" android:src="@mipmap/ic_launcher"/> <LinearLayout android:id="@+id/layout_content" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingTop="@dimen/image_height"> <!-- YOUR CONTENT HERE --> </LinearLayout> </FrameLayout> </ScrollView> 

And in your code, you move the image on the scroll:

 final ImageView image = (ImageView) findViewById(R.id.image); ((ScrollView) rootView.findViewById(R.id.scroll_adinfo)).getViewTreeObserver().addOnScrollChangedListener( new ViewTreeObserver.OnScrollChangedListener() { @Override public void onScrollChanged() { int scrollY = ((ScrollView) rootView.findViewById(R.id.scroll_adinfo)).getScrollY(); image.setY(scrollY / 2); } }); 

I extracted this from one of my projects and edited it so that I could skip something.

0
Dec 22 '15 at 17:50
source share



All Articles