AppBarLayout+ToolBar+CollapsingToolbarLayout+NestedScrollView

本文介绍了AppBarLayout作为AppBar的容器,它需要依赖CoordinatorLayout,并与ToolBar和CollapsingToolbarLayout配合使用。ToolBar是Material Design风格的导航控件,允许自定义布局并设置导航图标、Logo等。CollapsingToolbarLayout提供了可折叠的Toolbar效果,常用于AppbarLayout中。NestedScrollView则是一个支持嵌套滑动的滚动视图,扩展了ScrollView的功能。

AppBarLayout:
AppBarLayout是继承LinearLayout的子类,根据名称可以知道它是AppBar的容器。

AppBarLayout需要注意几点:

  • 让子View可以选择自己的滑动的方式。
  • 需要依赖CoordinatorLayout作为父容器,同时也要求一个具有可以独立滚动的兄弟节点(或兄弟节点的子view可以滚动)才能发挥其功能。

AppBarLayout一般经常与ToolBar和CollapsingToolbarLayout一起使用。

ToolBar:

ToolBar是android 与Android 5.0开始推出的Material Design风格的导航控件,用来取代ActionBar。tionBar相比,Toolbar明显灵活多了,它不像ActionBar一样固定在Activity的顶部,而是可以放在界面的任意地方。并且ToolBar可以有很多定制的余地,定制的属性在API文档中都有详细的介绍。

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/activity_tool_bar_app_bar"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        app:popupTheme="@style/PoPupMenu">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="控件"/>

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

</LinearLayout>

设置导航图标、app的logo、主标题和子标题:

//设置导航图标
    mToolbar.setNavigationIcon(R.mipmap.ic_drawer_home);
    mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Toast.makeText(mActivity, "导航图标", Toast.LENGTH_SHORT).show();
        }
    });

    //设置logo
    mToolbar.setLogo(R.mipmap.ic_launcher);

    //设置主标题
    mToolbar.setTitle("Title");
    mToolbar.setTitleTextColor(Color.WHITE);

    //设置子标题
    mToolbar.setSubtitle("subTitle");

也可以通过在布局文件中设置:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/activity_tool_bar_app_bar"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        app:navigationIcon="@mipmap/ic_drawer_home"
        app:logo="@mipmap/ic_launcher"
        app:title="title"
        app:titleTextColor="@android:color/white"
        app:subtitle="subtitle"
        app:popupTheme="@style/PoPupMenu">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="控件"/>

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

</LinearLayout>

注意:设置这些图片的时候,使用在根布局中加入自定义属性的命名空间

xmlns:app="http://schemas.android.com/apk/res-auto"

然后再布局中使用这些命名空间。

设置Actionmenu:

效果图:

base_toolbar_menu:

<menu xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto">

    <item
        android:id="@id/action_search"
        android:icon="@mipmap/ic_search_white_24dp"
        android:title="@string/menu_search"
        app:showAsAction="ifRoom" />

    <item
        android:id="@id/action_notification"
        android:icon="@mipmap/ic_notifications"
        android:title="@string/menu_notifications"
        app:showAsAction="ifRoom" />

    <item
        android:id="@+id/action_item1"
        android:title="@string/item_01"
        app:showAsAction="never" />

    <item
        android:id="@+id/action_item2"
        android:title="@string/item_02"
        app:showAsAction="never" />

</menu>

//showAsAction这个属性的值有: 
//1、always:使菜单项一直显示在ToolBar上。 
//2、ifRoom:如果有足够的空间,这个值会使菜单项显示在ToolBar上。 
//3、never:使菜单项永远都不出现在ToolBar上,在…的子项中显示。 
//4、withText:使菜单项和它的图标,菜单文本一起显示。

函数中:

mToolbar.inflateMenu(R.menu.base_toolbar_menu);
    mToolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
        @Override
        public boolean onMenuItemClick(MenuItem item) {
            switch (item.getItemId()){
                case R.id.action_search:
                    Toast.makeText(mActivity, "搜索", Toast.LENGTH_SHORT).show();
                    break;
                case R.id.action_notification:
                    Toast.makeText(mActivity, "通知", Toast.LENGTH_SHORT).show();
                    break;
                case R.id.action_item1:
                    Toast.makeText(mActivity, "item1", Toast.LENGTH_SHORT).show();
                    break;
                case R.id.action_item2:
                    Toast.makeText(mActivity, "item2", Toast.LENGTH_SHORT).show();

                    break;
                default:break;
            }
            return false;
        }
    });

如果想要修改弹出框的背景色和字体的颜色的话:

<style name="PoPupMenu" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:colorBackground">@color/colorAccent</item>
    <item name="android:textColor">@android:color/white</item>
    <item name="android:overlapAnchor">false</item>
</style>

然后再布局文件中引用:

<android.support.v7.widget.Toolbar
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:background="?attr/colorPrimary"
    app:navigationIcon="@mipmap/ic_drawer_home"
    app:logo="@mipmap/ic_launcher"
    app:title="title"
    app:titleTextColor="@android:color/white"
    app:subtitle="subtitle"
    app:popupTheme="@style/PoPupMenu"
    >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="控件"/>

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

效果图:

注意:
网上看到说,将overlapanchor设置成false之后,弹出框会显示在toolbar的下面,但是我这里却没有这种能够效果,也不知道什么原因

CollapsingToolbarLayout:

CollapsingToolbarLayout包裹 Toolbar 的时候提供一个可折叠的 Toolbar,一般作为AppbarLayout的子视图使用。

NestedScrollView:

它是support-v4包提供的控件,继承至FrameLayout, 并实现了NestedScrollingParent,NestedScrollingChild, ScrollingView接口。它的作用类似于Android.widget.ScrollView,不同点在于NestedScrollView支持嵌套滑动。

<think> 嗯,用户提出了一个Android开发中嵌套滑动组件的典型问题,涉及CoordinatorLayout家族组件的交互细节。从用户引用的资料来看,ta已经做了不少调研——引用1提到多层RecyclerView嵌套导致的颤抖问题,引用3详细说明了CollapsingToolbarLayout的滑动标志位配置,引用4则展示了通过触摸事件干预滑动行为的技巧。用户明显是个有经验的开发者,可能正在调试复杂布局。 用户的核心诉求很明确:为什么AppBarLayout有时会"卡住",必须等RecyclerView先滑动才能响应?这其实涉及到CoordinatorLayout嵌套滑动机制的三个关键点: 首先是滑动标志位配置问题。CollapsingToolbarLayout如果没有正确设置scroll|enterAlways这类flag,AppBarLayout就无法主动发起滑动,这正是引用3强调的重点。需要检查XML里是否漏掉scroll这个基础flag。 其次是焦点抢占的矛盾。当RecyclerView内容区域获取焦点时(比如包含EditText),触摸事件会被优先消费,导致AppBarLayout失去滑动机会。这时候需要像引用4那样主动干预事件分发,但更优雅的解法应该是清除RecyclerView内部控件的焦点。 最后是嵌套滚动链断裂的特殊情况。如果RecyclerView外层还有ScrollView等容器,或者启用了特殊的分页模式,可能破坏CoordinatorLayout的滑动协调机制。这时就需要继承RecyclerView重写onInterceptTouchEvent,或者设置NestedScrollingChild3接口强制启用嵌套滑动。 用户没有提及具体场景,所以需要给出阶梯式解决方案:从最简单的XML配置检查开始(80%问题可能出在这里),再进阶到焦点管理和自定义嵌套滚动逻辑。考虑到ta引用的代码片段里有触摸事件拦截的尝试,应该特别说明ViewCompat.stopNestedScroll的正确用法,避免出现引用4方案中可能导致的滑动卡顿。 有趣的是引用2提到NestedScrollView替代RecyclerView的解法,这其实暗示了问题的本质:RecyclerView自身嵌套滑动支持需要显式激活(setNestedScrollingEnabled)。或许该提醒用户对比测试NestedScrollView的行为,能更快定位问题根源。 </think> 在 `CoordinatorLayout` + `AppBarLayout` + `CollapsingToolbarLayout` + `RecyclerView` 组合中,**AppBarLayout 无法立即滑动而需先滑动 RecyclerView** 的问题通常由以下原因及解决方案造成: --- ### **原因分析** 1. **滑动标志位(`layout_scrollFlags`)配置错误** - `CollapsingToolbarLayout` 的子视图(如 `Toolbar`)未正确设置 `app:layout_scrollFlags`,导致 CoordinatorLayout 无法识别滑动行为。 - 错误示例:未包含 `scroll` 标志位。 2. **嵌套滑动冲突** - RecyclerView 未启用嵌套滑动(`setNestedScrollingEnabled(false)`),或被父布局拦截事件。 - RecyclerView 内容未填满屏幕时,可能无法触发 AppBarLayout 的折叠[^3]。 3. **焦点抢占问题** - RecyclerView 的子项(如 EditText)获取焦点时,触摸事件优先传递给子项,导致 AppBarLayout 无法响应滑动。 4. **布局层级或滚动方向限制** - 嵌套多层 RecyclerView 或使用了不支持嵌套滑动的容器(如 ScrollView),破坏滑动链[^1]。 --- ### **解决方案** #### 1. **检查滑动标志位配置** ```xml <com.google.android.material.appbar.CollapsingToolbarLayout app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"> <!-- Toolbar/ImageView 等子视图 --> <androidx.appcompat.widget.Toolbar app:layout_collapseMode="pin"/> <!-- 固定Toolbar --> </com.google.android.material.appbar.CollapsingToolbarLayout> ``` - **关键点**:确保 `layout_scrollFlags` 包含 `scroll`(基础滑动标志)和 `exitUntilCollapsed`(折叠至最小高度)[^3]。 #### 2. **启用嵌套滑动** ```java recyclerView.setNestedScrollingEnabled(true); // 默认true,若被禁用需启用 recyclerView.setHasFixedSize(true); // 优化性能 ``` - 若 RecyclerView 外层还有 ScrollView,改为 `NestedScrollView` 并设置: ```xml <androidx.core.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"> ``` #### 3. **解决焦点抢占** ```java // 在Activity中清除RecyclerView内部控件的焦点 recyclerView.setOnTouchListener((v, event) -> { if (event.getAction() == MotionEvent.ACTION_DOWN) { v.clearFocus(); // 清除子项焦点 ViewCompat.stopNestedScroll(recyclerView); // 停止遗留滑动[^4] } return false; }); ``` #### 4. **强制传递滑动事件** ```java // 自定义RecyclerView,重写事件分发 public class FixRecyclerView extends RecyclerView { @Override public boolean dispatchTouchEvent(MotionEvent e) { getParent().requestDisallowInterceptTouchEvent(true); // 禁止父布局拦截事件 return super.dispatchTouchEvent(e); } } ``` #### 5. **检查布局约束** - 确保 RecyclerView 的高度设置为 `match_parent` 而非 `wrap_content`,避免内容不足时无法触发折叠。 - 移除不必要的嵌套滚动容器(如多层 RecyclerView),改用单一 `NestedScrollView`[^1][^2]。 --- ### **总结流程** 1. **检查 XML 标志位** → 2. **启用嵌套滑动** → 3. **处理焦点抢占** → 4. **优化布局层级**。 若仍无效,通过自定义事件分发或滑动行为拦截遗留滑动趋势[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值