Android AppBarLayout的使用以及AppBarLayout嵌套滚动不连贯的问题

先上图:
这里写图片描述

实现上图效果,首先来了解两个知识点:

1、AppBarLayout子布局的5种滚动标识(即app:layout_scrollFlags属性)

scroll

Child View 伴随着滚动事件而滚出或滚进屏幕。如果使用了其他值,必定要使用这个值才能起作用。

示例XML代码:

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

        <android.support.v7.widget.Toolbar
            xmlns:app="http://schemas.android.com/apk/res-auto"
            android:id="@+id/tb_toolbar"
            android:layout_width="match_parent"
            android:layout_height="@dimen/dp_56"
            app:titleTextColor="@color/white"
            app:title="@string/app_name"
            app:theme="@style/OverFlowMenuTheme"
            app:popupTheme="@style/AppTheme"
            android:background="@color/blue"
            app:layout_scrollFlags="scroll"/>

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

对应效果图:
这里写图片描述

enterAlways

快速返回模式。其实就是向下滚动时Scrolling View和Child View之间的滚动优先级问题。对比scroll和scroll | enterAlways设置,发生向下滚动事件时,前者优先滚动Scrolling View,后者优先滚动Child View,当优先滚动的一方已经全部滚进屏幕之后,另一方才开始滚动。

示例XML代码:

...
app:layout_scrollFlags="scroll|enterAlways"
...

对应效果图:
这里写图片描述

enterAlwaysCollapsed

enterAlways的附加值。这里涉及到Child View的高度和最小高度,向下滚动时,Child View先向下滚动最小高度值,然后Scrolling View开始滚动,到达边界时,Child View再向下滚动,直至显示完全。

示例XML代码:

...
android:layout_height="@dimen/dp_200"
android:minHeight="@dimen/dp_56"
...
app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed"
...

对应效果图:
这里写图片描述

exitUntilCollapsed

这里也涉及到最小高度。发生向上滚动事件时,Child View向上滚动退出直至最小高度,然后Scrolling View开始滚动。也就是,Child View不会完全退出屏幕。

示例XML代码:

...
android:layout_height="@dimen/dp_200"
android:minHeight="@dimen/dp_56"
...
app:layout_scrollFlags="scroll|exitUntilCollapsed"
...

这里写图片描述

snap

简单理解,就是Child View滚动比例的一个吸附效果。也就是说,Child View不会存在局部显示的情况,滚动Child View的部分高度,当我们松开手指时,Child View要么向上全部滚出屏幕,要么向下全部滚进屏幕,有点类似ViewPager的左右滑动。

示例XML代码:

...
android:layout_height="@dimen/dp_200"
...
app:layout_scrollFlags="scroll|snap"
...

对应效果图:
这里写图片描述

2、CollapsingToolbarLayout子布局的3种折叠模式(即app:layout_collapseMode属性)

off

这个是默认属性,布局将正常显示,没有折叠的行为。

pin

CollapsingToolbarLayout折叠后,此布局将固定在顶部。(本文Toolbar的app:layout_collapseMode属性就是这个)

parallax

CollapsingToolbarLayout折叠时,此布局也会有视差折叠效果。

了解基础知识后再去实现本文效果。

XML代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical">

    <android.support.design.widget.CoordinatorLayout
        android:id="@+id/coordinator_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true">

        <android.support.design.widget.AppBarLayout
            android:id="@+id/app_bar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#fff"
            app:elevation="0dp">

            <android.support.design.widget.CollapsingToolbarLayout
                android:id="@+id/main.collapsing"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:minHeight="?attr/actionBarSize"
                app:collapsedTitleGravity="center_horizontal"
                app:layout_scrollFlags="scroll|exitUntilCollapsed">

                <ImageView
                    android:id="@+id/usercenter_bg"
                    android:layout_width="match_parent"
                    android:layout_height="200dp"
                    android:scaleType="centerCrop"
                    android:src="@mipmap/dog"/>

                <!-- 标题 -->
                <android.support.v7.widget.Toolbar
                    android:id="@+id/toolbar"
                    android:layout_width="match_parent"
                    android:layout_height="?attr/actionBarSize"
                    android:background="#00000000"
                    app:layout_collapseMode="pin">

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="AppBarLayout"
                        android:textColor="@color/colorWhite"
                        android:textSize="18sp"/>
                </android.support.v7.widget.Toolbar>
            </android.support.design.widget.CollapsingToolbarLayout>

            <!-- 此处可替换为指示器 -->
            <TextView
                android:id="@+id/usercenter_title_mic"
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:background="@color/color_material_light"
                android:gravity="center"
                android:text="我是悬浮的">
            </TextView>
        </android.support.design.widget.AppBarLayout>

        <android.support.v7.widget.RecyclerView
            android:id="@+id/appbar_recyclerview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">
        </android.support.v7.widget.RecyclerView>
    </android.support.design.widget.CoordinatorLayout>

</LinearLayout>

需要注意三点:
1、CollapsingToolbarLayout作为AppBarLayout的子布局,其app:layout_scrollFlags属性设为scroll|exitUntilCollapsed,即CollapsingToolbarLayout向上滚动退出直至最小高度,然后AppBarLayout开始滚动。也就是,CollapsingToolbarLayout不会完全退出屏幕。注意要给CollapsingToolbarLayout设置android:minHeight属性。
2、Toolbar作为CollapsingToolbarLayout的子布局,其app:layout_collapseMode属性设为pin,即CollapsingToolbarLayout折叠后,此布局将固定在顶部。
3、RecyclerView的app:layout_behavior属性需要设为@string/appbar_scrolling_view_behavior。没有设置的话,AppBarLayout将不会响应滚动布局(Recyclerview、NestedScrollView等)的滚动事件。

然后运行项目即可实现本文效果。不过细心地盆友会发现,当CollapsingToolbarLayout收缩的时候,往下滑动RecyclerView的时候,CollapsingToolbarLayout伸展会很不连贯。因此我们要对AppBarLayout进行优化,使整体滑动连贯起来。
大概思路是,当RecyclerView滚动到顶部的时候,根据当前滑动的速度进行判断,是否让AppBarLayout被动展开(appBarLayout.setExpanded(true, true))。

首先定义接口OnAppbarExpandListener,用于通知AppBarLayout是否展开:

public interface OnAppbarExpandListener
{
    void onExpand();
}

然后在Activity中实现该接口:

    @Override
    public void onExpand()
    {
        //AppBarLayout展开
        appBarLayout.setExpanded(true, true);
    }

接着编写RvScrollListener类,在滚动中判断AppBarLayout展开时机:

    /**
     * 判断RecyclerView是否滚动到顶部,从而对AppBarLayout进行伸展
     */
    class RvScrollListener extends RecyclerView.OnScrollListener
    {
        OnAppbarExpandListener onAppbarExpandListener;
        int scrollY = 0;

        public RvScrollListener(OnAppbarExpandListener onAppbarExpandListener)
        {
            this.onAppbarExpandListener = onAppbarExpandListener;
        }

        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState)
        {
            super.onScrollStateChanged(recyclerView, newState);
            //判断快速滚动:当速度大于10且滚到顶部时,让AppBarLayout展开
            if (newState == RecyclerView.SCROLL_STATE_IDLE)
            {
                if (!recyclerView.canScrollVertically(-1) && scrollY < -10)
                {
                    onAppbarExpandListener.onExpand();//通知AppBarLayout伸展
                    scrollY = 0;
                }
            }
            //判断慢速滚动:当滚动到顶部时靠手指拖动后的惯性让RecyclerView处于Fling状态时的速度大于5时,让AppBarLayout展开
            if (newState == RecyclerView.SCROLL_STATE_SETTLING)
            {
                if (!recyclerView.canScrollVertically(-1) && scrollY < -5)
                {
                    onAppbarExpandListener.onExpand();
                    scrollY = 0;
                }
            }
        }

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy)
        {
            super.onScrolled(recyclerView, dx, dy);
            scrollY = dy;
        }
    }

最后给RecyclerView添加滚动监听addOnScrollListener:

mRecyclerView.addOnScrollListener(new RvScrollListener(this));

即完成对AppBarLayout嵌套滚动不连贯的优化。

源码地址:github

参考文章:Android 详细分析AppBarLayout的五种ScrollFlags

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要将 AppBarLayout 与 RecyclerView 使用,需要在布局文件中将它们嵌套在一起。具体实现步骤如下: 1. 在布局文件中定义 AppBarLayoutToolbar 控件,用于显示顶部工具栏和标题栏。 ```xml <android.support.design.widget.CoordinatorLayout android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:layout_scrollFlags="scroll|enterAlways" /> </android.support.design.widget.AppBarLayout> </android.support.design.widget.CoordinatorLayout> ``` 2. 在 AppBarLayout 内部添加一个可折叠式的标题栏控件(CollapsingToolbarLayout),用于显示标题和背景图片等内容。 ```xml <android.support.design.widget.CollapsingToolbarLayout android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_scrollFlags="scroll|exitUntilCollapsed"> <ImageView android:id="@+id/image_view" android:layout_width="match_parent" android:layout_height="200dp" android:scaleType="centerCrop" android:src="@drawable/header_image" 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" /> </android.support.design.widget.CollapsingToolbarLayout> ``` 3. 在布局文件中定义 RecyclerView 控件,用于显示列表内容。 ```xml <android.support.v7.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" /> ``` 4. 在相应的 Activity 或 Fragment 中获取 RecyclerView 对象,并设置 Adapter 和 LayoutManager。 ```java RecyclerView recyclerView = findViewById(R.id.recycler_view); recyclerView.setAdapter(adapter); recyclerView.setLayoutManager(layoutManager); ``` 5. 在 AppBarLayout 中设置滚动监听器(OnOffsetChangedListener),根据滚动距离和状态改变工具栏的样式、大小和位置等效果。 ```java AppBarLayout appBarLayout = findViewById(R.id.app_bar_layout); appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() { @Override public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { // 根据 verticalOffset 计算工具栏的高度和透明度等属性 // 更新工具栏的样式和位置等 } }); ``` 这样就可以实现一个带有 AppBarLayout 和 RecyclerView 的可滚动界面了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值