如何禁用NestedScrollView&CollapsingToolbarLayout的滚动,例如当下面没有更多的内容时?

背景

我尝试添加与许多应用程序中显示的function相同的function,屏幕的上部区域根据滚动的内容缩小和展开。

为此,我使用Google的devise库,如CheeseSquare示例所示。

问题

事实上,无论NestedScrollView中有多less内容,它都可以让我滚动到内容的最后一个视图的下方,让我看到操作栏的最终状态,具有最小的尺寸。

总之,这是我滚动到底部时看到的(CheeseSquare样本的修改内容):

在这里输入图像说明

而这是我想要滚动到底部(从联系人应用程序):

在这里输入图像说明

我也试图修复ThreePhasesBottomSheet示例中的一个bug,即使它处于偷看状态,也可以在底部表单内容中滚动。 要重现,开始水平滚动(没有任何事情,因为没有什么可以滚动这种方式),然后垂直,这将以某种方式触发滚动底部的内容。

因此,我需要禁用那里的“transformView()”方法,在“translation”的情况下滚动

这是如何使用正常的用法:

在这里输入图像说明

这就是它的行为与不阻止滚动的错误:

在这里输入图像说明

我试过了

我试图玩“ layout_scrollFlags ”标志,将高度更改为wrap_content,并删除clipToPadding和fitsSystemWindows属性。

这里是示例XML文件,我已经修改,只包括一个cardView而不是许多:

<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> 

我也尝试了下一个代码:

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

但是这仍然允许在CheeseSquare示例中滚动NestedScrollView本身,并且还允许在ThreePhasesBottomSheet示例中抛出

问题

  1. 当没有更多的内容显示在底部时,我可以做些什么来使滚动停止?

  2. 另外,我可以做什么来禁用NestedScrollView滚动的任何时候,我希望(为ThreePhasesBottomSheet示例)? 像“setEnableScrolling(…)”?

    我试图扩展NestedScrollView,也从ScrollingViewBehavior扩展,但没有find可以做什么来禁用滚动。

这可能是一个非常简单的事情,但我找不到什么…

编辑:如果需要,这是我目前使用的devise和支持库

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

编辑:对于#2,我已经find了BottomSheetLayout.java文件中的一个解决方法,以禁用所有与variables“sheetViewOwnsTouch”相关的,就好像它总是设置为“false”。 这将允许在底部表单上窃取触摸事件。 但是,这只是一个解决方法,只适用于这种情况。 它也会导致一些本应该由其他视图处理的触摸事件。 我仍然希望知道如何以编程方式阻止滚动,并且还有足够的空间显示内容的情况。

当没有 更多的内容显示在底部 时,我可以做些什么来使滚动停止

首先,正如我在下面评论的,你在问题中说的滚动不是NestedScrollView 。 它属于CollapsingToolbarLayoutNestedScrollView的滚动事件只发生在CollapsingToolbarLayout完全崩溃的时候,当它没有更多的内容(底部到达)的时候它将停止滚动。 对于CollapsingToolbarLayout ,它会折叠到它的工具栏的layout_height(就像在xml文件中,你会发现"?attr/actionBarSize" )。 下面的图片将演示,注意红色矩形是工具栏(我设置它的背景)

BNK的形象

因此,要为您的#1解决scheme,您需要计算NestedScrollView的高度,然后如果它小于屏幕高度,我们修复工具栏的高度。

总之,你可以更新activity_detail.xml如下:

 <?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> 

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

结果如下:

BNK的截图

使用Cheesesquare示例,我已经定制了这个项目并上传到My GitHub 。 我同意,它仍然有一些问题,但是,至less它可以为您的第一个问题的解决scheme。

请看一下。 希望能帮助到你!

要禁用滚动,只需将NestedScrollView和LinearLayout的子高度都设置为'wrap_content'。

这不会完全按照你的意愿,但至less它不会滚动,如果内容完全适合在屏幕上。

谈到你的联系人应用程序的例子,看起来好像没有使用CoordinatorLayout和其他东西。

这种行为可以通过这种方式完成:

 <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> 

在您的代码中,您将滚动移动图像:

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

我已经从我的一个项目中提取了它,并对其进行了编辑,以便我可以错过一些东西