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

Posted

技术标签:

【中文标题】如何禁用 NestedScrollView&CollapsingToolbarLayout 的滚动,例如当下面没有更多内容时?【英文标题】:How to disable scrolling of NestedScrollView&CollapsingToolbarLayout, for example when there is no more content below? 【发布时间】:2016-02-11 09:36:05 【问题描述】:

背景

我尝试添加与许多应用程序相同的功能,其中屏幕的上部区域根据滚动的内容缩小和扩大。

为此,我使用 Google 的设计库,如 the CheeseSquare sample 所示。

问题

问题是,无论 NestedScrollView 中有多少内容,它都可以让我滚动到内容的最后一个视图下方,只是为了让我看到操作栏的最终状态,它本身的大小是最小的。

简而言之,这是我滚动到底部时看到的(CheeseSquare 示例的修改内容):

虽然这是我在滚动到底部时想要的(取自联系人应用程序):

我还在尝试修复ThreePhasesBottomSheet 示例中的一个错误,即即使处于窥视状态,也可以在底部工作表内容中滚动。要重现,开始水平滚动(这不会做任何事情,因为没有任何东西可以这样滚动)然后垂直滚动,这会以某种方式触发底页内容的滚动。

因此,我需要在“transformView()”方法中禁用滚动,以防“翻译

这是正常使用时的工作方式:

这就是它在不阻止滚动的错误时的行为方式:

我尝试过的

我尝试使用“layout_scrollFlags”标志,将高度更改为 wrap_content,并删除 clipToPadding 和 fitSystemWindows 属性。

这是示例 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_
    android:layout_
    android:fitsSystemWindows="true">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_
        android:layout_
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        android:fitsSystemWindows="true">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_
            android:layout_
            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_
                android:layout_
                android:scaleType="centerCrop"
                android:fitsSystemWindows="true"
                app:layout_collapseMode="parallax" />

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_
                android:layout_
                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_
        android:layout_
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <LinearLayout
            android:layout_
            android:layout_
            android:orientation="vertical"
            android:paddingTop="24dp">

            <android.support.v7.widget.CardView
                android:layout_
                android:layout_
                android:layout_margin="@dimen/card_margin">

                <LinearLayout
                    style="@style/Widget.CardContent"
                    android:layout_
                    android:layout_>

                    <TextView
                        android:layout_
                        android:layout_
                        android:text="Info"
                        android:textAppearance="@style/TextAppearance.AppCompat.Title" />

                    <TextView
                        android:layout_
                        android:layout_
                        android:text="@string/cheese_ipsum" />

                </LinearLayout>

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

        </LinearLayout>

    </android.support.v4.widget.NestedScrollView>

    <android.support.design.widget.FloatingActionButton
        android:layout_
        android:layout_
        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 示例中滚动。

问题

    当底部没有更多内容可显示时,我该怎么做才能使滚动停止?

    此外,我可以在任何时候禁用 NestedScrollView 的滚动(对于 ThreePhasesBottomSheet 示例)?像“setEnableScrolling(...)”这样的东西?

    我尝试扩展 NestedScrollView 并从 ScrollingViewBehavior 扩展,但未能找到禁用滚动的方法。

改起来大概是个很简单的事情,但是我不知道是什么...

编辑:如果需要,这是我目前用于设计和支持库的内容

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

编辑:对于#2,我从 BottomSheetLayout.java 文件中找到了一种解决方法,以禁用与变量“sheetViewOwnsTouch”相关的所有内容,就好像它始终设置为“false”一样。这将允许窃取底部工作表上的触摸事件。但是,这只是一种解决方法,并且仅适用于这种情况。它还会导致一些应该由其他视图处理的触摸事件。我仍然想知道如何以编程方式阻止滚动,以及在足够空间显示内容的另一种情况下。

【问题讨论】:

不知道,但请提供您使用的库版本,以及您如何实现视图(滚动标志等) 我只更改了布局的内容(使用 textViews 而不是 cardViews)来显示这些屏幕截图。我已经更新了问题以显示库版本。为什么要对此投反对票? 抱歉,我认为这不是我对您的问题投反对票的原因。反正我去看看 @TunaKarakasoglu 很有趣。你能示范一下吗? @Virus 首先将屏幕捕获为视频文件(使用 ADB 或 Android Studio),然后使用您希望使用的任何工具将其转换为 gif,例如:image.online-convert.com/convert-to-gif 【参考方案1】:

如果没有,我该怎么做才能使滚动停止 底部显示更多内容?

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

所以要为您的#1 找到解决方案,您需要计算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_
    android:layout_
    android:fitsSystemWindows="true">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_
        android:layout_
        android:fitsSystemWindows="true"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_
            android:layout_
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <ImageView
                android:id="@+id/backdrop"
                android:layout_
                android:layout_
                android:fitsSystemWindows="false"
                android:scaleType="centerCrop"
                app:layout_collapseMode="parallax" />

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_
                android:layout_
                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_
        android:layout_            
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <LinearLayout
            android:id="@+id/linearLayout1"
            android:layout_
            android:layout_
            android:orientation="vertical">

            <android.support.v7.widget.CardView
                android:layout_
                android:layout_
                android:layout_margin="@dimen/card_margin">

                <LinearLayout
                    style="@style/Widget.CardContent"
                    android:layout_
                    android:layout_>

                    <TextView
                        android:layout_
                        android:layout_
                        android:text="Info"
                        android:textAppearance="@style/TextAppearance.AppCompat.Title" />

                    <TextView
                        android:layout_
                        android:layout_
                        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;
    

结果如下:

通过Cheesesquare示例,我已经定制了这个项目并上传到My GitHub。我同意它仍然存在一些问题,但是,至少它可以解决您的第一个问题。

请看一看。希望对您有所帮助!

【讨论】:

根据您展示的动画,这效果不佳,因为工具栏没有固定,标题的文本也没有移动和调整大小。这类似于只放置一个带有内容的滚动视图...... 你能解释一下你做了什么,你在哪里阻止滚动?它对我提供的第二个样品(三相底板)也有帮助吗? 正如你在我的代码中看到的,我没有对 NestedScrollView 做任何事情。实际上,NSV 的滚动事件只有在 Toolbar 固定到 actionbar 或 Toolbar 的 layout_height 固定时才会发生。 CollapsingToolbarLayout 依赖于 Toolbar 的 layout_height,所以我计算了 linearLayout1 的运行时高度,然后在 IF 中设置 Toolbar 的 layout_height。我不确定这是否适用于#2。 linearLayout1的高度当然和NestedScrollView有关(对不起我的英文,我没有太多话可以解释清楚):) @BNK 为什么我应该在我的 #1 案例中更改它?我不需要更改工具栏的大小。当底部没有更多内容可滚动时,我想停止滚动。【参考方案2】:

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

这不会完全如你所愿,但至少它不会滚动,如果内容完全适合屏幕。

谈到您的通讯录应用示例,看起来它没有使用 CoordinatorLayout 和它附带的其他东西。

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

<ScrollView
    android:id="@+id/scroll_adinfo"
    android:layout_
    android:layout_>

    <FrameLayout
        android:layout_
        android:layout_
        android:orientation="vertical">

        <ImageView
            android:id="@+id/image"
            android:layout_
            android:layout_
            android:src="@mipmap/ic_launcher"/>

        <LinearLayout
            android:id="@+id/layout_content"
            android:layout_
            android:layout_
            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);
                
            );

我已经从我的一个项目中提取了它并对其进行了编辑,因此我可以遗漏一些东西。

【讨论】:

“wrap_content”解决方案并不总是有效。例如,将第一项(在 LinearLayout 中)设置为示例中的卡片,将第二项设置为具有 textSize="20dp" 和 layout_marginTop="80dp" 的 TextView。它将允许滚动太多,直到操作栏折叠并且 TextView 下方有一个巨大的空白区域。在 Galaxy S4 上测试。但正如你所说,它并不完美。我不明白第二种解决方案。你试过了吗? @androiddeveloper 第二个解决方案代码是从我的一个项目中提取的。但它使用的是简单的 ScrollView。我不知道如何使它与 NestedScrollView 和 CoordinatorLayout 与 FloatingActionButton 一起工作。 @androiddeveloper 这个想法是将图像放在主要内容下方,并在用户滚动内容时以编程方式移动它。 好吧,这不是我问的... :( @androiddeveloper 这就是您的联系人应用示例中发生的情况。

以上是关于如何禁用 NestedScrollView&CollapsingToolbarLayout 的滚动,例如当下面没有更多内容时?的主要内容,如果未能解决你的问题,请参考以下文章

如何以编程方式在 NestedScrollView 中显示滚动条。

如何在Android中设置NestedScrollView的最大高度?

滚动 NestedScrollView 时如何获取 recyclerview 的当前项目位置?

当 Recyclerview 在 NestedScrollview 中时,如何避免绑定所有项目?

如何使用里面的 ListView 滚动 NestedScrollView?

如何在viewPager的视图顶部使用nestedScrollView中的viewpager