android - 展开 CollapsingToolbarLayout 时折叠内容而不是滚动

标签 android android-collapsingtoolbarlayout

我用 Android 的 CollapsingToolbarLayout 创建了一个简单的项目,这是它的结构(问题底部的完整布局源):

CoordinatorLayout
  AppBarLayout
    CollapsingToolbarLayout
      Toolbar
  RelativeLayout (layout_behavior="@string/appbar_scrolling_view_behavior")
    TextView (layout_alignParentTop="true")
    TextView (layout_alignParentBottom="true")

当我展开/折叠栏时, View 滚动并且底部 View 超出屏幕: enter image description here

我要实现的是以底部文本始终保持可见的方式折叠/收缩(而不是滚动)内容(我的 RelativeLayout):

enter image description here enter image description here

我如何在 Android 上执行此操作?

这是我的完整布局:

<?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"
    android:fitsSystemWindows="true">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="@dimen/app_bar_height"
        android:fitsSystemWindows="true"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.design.widget.CollapsingToolbarLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|exitUntilCollapsed"
            app:toolbarId="@+id/toolbar">

            <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/AppTheme.PopupOverlay"/>

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

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:text="The text on the top"
            android:textSize="32sp"/>

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:text="The text on the bottom"
            android:textSize="32sp"/>
    </RelativeLayout>

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

最佳答案

这里真正的问题是如何在应用栏更改高度时正确调整 RelativeLayout 的大小。在查看如何执行此操作之前,我们需要更改 XML 布局。

来自documentation for AppBarLayout :

AppBarLayout also requires a separate scrolling sibling in order to know when to scroll.

由于 RelativeLayout` 不符合“滚动同级”的条件,因此我们需要将其封装在“NestedScrollView”之类的组件中。这是更新后的 XML 文件:

activity_main.xml

<android.support.design.widget.CoordinatorLayout 
    android:id="@+id/coordinatorLayoutProfile"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context=".MainActivity">

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

        <android.support.design.widget.CollapsingToolbarLayout
            android:layout_width="match_parent"
            android:layout_height="220dp"
            android:background="@color/colorPrimary"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

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

        <RelativeLayout
            android:id="@+id/relativeLayout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@android:color/holo_blue_light">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_alignParentTop="true"
                android:text="The text on the top"
                android:textSize="32sp" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_alignParentBottom="true"
                android:text="The text on the bottom"
                android:textSize="32sp" />
        </RelativeLayout>
    </android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>

我可能对 XML 进行了一些其他更改以使其在我的环境中正常工作,但除了插入 NestedScrollView 之外应该没有实质性更改。

RelativeLayout 大小的更改将在代码中设置,并由 AppBarLayout.OnOffsetChangedListener 触发。 .我们将根据应用栏的垂直偏移计算和更改 RelativeLayout 的大小。

MainActivity.java

public class MainActivity extends AppCompatActivity {
    private RelativeLayout mRelativeLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        mRelativeLayout = findViewById(R.id.relativeLayout);
        final AppBarLayout appBarLayout = findViewById(R.id.appBar);
        final int screenHeight = getResources().getDisplayMetrics().heightPixels;

        appBarLayout.post(new Runnable() {
            @Override
            public void run() {
                adjustRelLayoutHeight(mRelativeLayout, screenHeight - appBarLayout.getBottom());
            }
        });

        appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
            @Override
            public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
                adjustRelLayoutHeight(mRelativeLayout, screenHeight - appBarLayout.getBottom());
            }
        });
    }

    private void adjustRelLayoutHeight(RelativeLayout layout, int newHeight) {
        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) layout.getLayoutParams();
        lp.height = newHeight;
        layout.setLayoutParams(lp);
    }

    private static final String TAG = "MainActivity";
}

结果如下:

enter image description here

更新:以下是使用 ViewTreeObserver.OnPreDrawListener() 的替代方法,可避免额外绘制。但是效果是一样的:

MainActivity.java(替代方法)

public class MainActivity extends AppCompatActivity {
    private RelativeLayout mRelativeLayout;
    private int mCoordinatorHeight;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        mRelativeLayout = findViewById(R.id.relativeLayout);
        final AppBarLayout appBarLayout = findViewById(R.id.appBar);

        final CoordinatorLayout coordinatorLayout =
            (CoordinatorLayout) findViewById(R.id.coordinatorLayoutProfile);
        // Wait for just before drawing the view to get its height.
        coordinatorLayout.getViewTreeObserver()
            .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                @Override
                public boolean onPreDraw() {
                    // Remove the listener so we don't go into an infinite loop.
                    coordinatorLayout.getViewTreeObserver().removeOnPreDrawListener(this);
                    mCoordinatorHeight = coordinatorLayout.getHeight();
                    adjustRelLayoutHeight(mRelativeLayout, mCoordinatorHeight - appBarLayout.getBottom());
                    return false; // abort drawing
                }
            });

        appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
            @Override
            public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
                adjustRelLayoutHeight(mRelativeLayout, mCoordinatorHeight - appBarLayout.getBottom());
            }
        });
    }

    private void adjustRelLayoutHeight(RelativeLayout layout, int newHeight) {
        if (newHeight <= 0) {
            // no-op if height is invalid
            return;
        }
        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) layout.getLayoutParams();
        if (lp.height != newHeight) {
            lp.height = newHeight;
            layout.setLayoutParams(lp);
        }
    }

    private static final String TAG = "MainActivity";
}

关于android - 展开 CollapsingToolbarLayout 时折叠内容而不是滚动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47076485/

相关文章:

android - 在 Android 9 中访问图像时出现 SecurityException

android - 在嵌套 ScrollView 中使用水平回收器 View 时,折叠工具栏布局不起作用

android - CollapsingToolbarLayout 标题在与侧抽屉重叠时消失

android - 滚动时单击不在 CoordinatorLayout 中的 RecyclerView 上工作

android - 使可折叠工具栏自动折叠/展开

java - 为什么这个 fragment 会导致我的程序在旋转时崩溃?

android - 如何从命令行使用 gradle 创建 android 项目?

Android - 通过软键盘输入在 Canvas 上绘制文本

android - 如何在 Android 中使用 NFC (Android Beam) 接收文件

android - CollapsingToolbarLayout 的不同 scrollFlags 之间的区别