如何模仿Lollipop的手机应用程序,在可滚动内容之前调整上层项目的大小?

and*_*per 10 android resize material-design android-recyclerview

背景

在Lollipop的手机应用程序中,当您到达"最近"或"联系人"选项卡,并且您尝试滚动时,首先发生的事情是调整上部区域的大小,其中包括最近的事件和搜索框,如下所示:

在此输入图像描述

如果RecyclerView上有超过3个项目,只要上部区域可以缩小到最小尺寸,RecyclerView就不会向下滚动.

向上滚动也是如此:只要上部区域没有完全放大,RecyclerView就不会向上滚动.

问题

我找不到实现此功能的最佳方法.

更具体地说,我对上部区域的大小调整有一个问题,因此它将在Lollipop上运行时一样平滑.

为了简化,我只需要调整屏幕的一部分,而不是手机的应用程序("最近的事件"和搜索框)上显示的2.

我试过的

我尝试过多种方法:

  1. 使RecyclerView变得像整个屏幕一样大,同时拥有一个假的,大的空头.当我滚动时,我还将"translationY"设置为顶部的真实内容.这有一个问题,显示滚动条作为上部区域的一部分(我想在正确的位置显示滚动条).此外,由于您必须处理其他页面的RecyclerViews滚动值,因此它非常复杂.这是一个类似于某些第三方库的解决方案,例如这个(在这里我使用了布局而不是ImageView,但代码几乎相同).

  2. RecyclerView位于上方区域下方,滚动会更改上方区域的layoutParams,类似于我在此帖子中所做的操作.

  3. 与2相同,但我更改了视图的scaleY,而不是更改LayoutParams.

对于#2和#3,问题是在某些情况下,只要我在某个值中滚动+ Y的事件,我也会得到相同值的-Y滚动(反之亦然) ,使调整大小效果的处理"跳跃"(上下,即使用户滚动得很好).

我猜测为什么会这样,当我移动RecyclerView时,用户做的下一个事件与原始事件完全不同,因为我改变了RecyclerView的定位方式或大小.

我尝试过使用setOnTouchListener(甚至与GestureDetectorCompat一起)和setOnScrollListener.所有这些都引起了同样奇怪的问题.

这个问题

我该如何解决这个问题?为什么会发生,为什么不总是发生?


编辑:我试图改变#2,所以我不会处理RecyclerView的触摸事件,而是处理其容器的触摸事件(一些LinearLayout).由于某种原因,容器没有响应触摸事件,所以我用RelativeLayout替换它,并在该布局内的所有内容上放置一个视图,这将响应触摸事件(并相应地更改上部区域).这很有效,但是在需要时我无法将事件进一步传递给子视图.

我认为最好的事情是自定义RecyclerView(扩展它)触摸处理.也许添加一个用于滚动的监听器,当RecyclerView即将滚动时,它会询问它是否正常,如果没有,它将不会尝试滚动直到触发事件被触发并重置其状态.

and*_*per 2

好的,一种解决方案(我仍然不喜欢,但有效)是使用一个“ TouchInterceptionFrameLayout ”类(来自我找到的),它允许您决定何时允许滚动,何时不允许滚动,当它不应该滚动时,您可以更改同时具有分页选项卡和 ViewPager 的布局的填充(或您希望的内容)。

viewPager&tabs 的容器覆盖整个区域,并且具有变化的填充。

这是布局:

        <LinearLayout
            android:id="@+id/header"
            android:layout_width="match_parent"
            android:orientation="vertical"
            android:layout_height="wrap_content">
            <!-- put upper content here -->

        </LinearLayout>

        <LinearLayout
            android:id="@+id/pagerAndTabsContainer"
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <com.astuetz.PagerSlidingTabStrip
                android:id="@+id/viewPagerSlidingTabsStrip"
                android:layout_width="match_parent"
                android:background="@color/default_background"
                android:layout_height="48dip"/>

            <android.support.v4.view.ViewPager
                android:background="@color/default_background"
                android:id="@+id/viewPager"
                android:layout_width="match_parent"
                android:layout_height="match_parent"/>
        </LinearLayout>


    </com.github.ksoichiro.android.observablescrollview.TouchInterceptionFrameLayout>
Run Code Online (Sandbox Code Playgroud)

然后,您需要一些初始化代码(当布局阶段完成并且您可以获得视图的实际大小时):

// the upper area height, that can be shrunk to a size of 0 height when needed
mResizeableViewHeight = mHeaderView.getHeight(); 
// set initial padding if you wish to show the upper area by default
mPagerAndTabsContainer.setPadding(0, mResizeableViewHeight, 0, 0); 
prepareViewPager(mViewPager); // set the pages and fragments...
// init the "TouchInterceptionFrameLayout" to handle touch events
mContentView.setScrollInterceptionListener(mInterceptionListener);
Run Code Online (Sandbox Code Playgroud)

在 TouchInterceptionFrameLayout.TouchInterceptionListener 的“shouldInterceptTouchEvent”函数上,您决定何时应该阻止触摸,并且在此接口的“onMoveMotionEvent”上,您应该处理被阻止的触摸。

对于每个具有 recyclerView 的片段,使用ObservableRecyclerView代替,并调用以下行:

    // get the fragment that shows the screen I've made (with the layout)
    Fragment fragment = getTargetFragment(); 
    // let the recyclerView handle filtered touches 
    mRecyclerView.setTouchInterceptionViewGroup(((IGetContainer) fragment).getContainer());
    // if you wish to put animations when you do a touch-up event, this may be handy (or use onUpOrCancelMotionEvent of the "TouchInterceptionListener" too/instead ) :
    if (fragment instanceof ObservableScrollViewCallbacks)                 
       mRecyclerView.setScrollViewCallbacks((ObservableScrollViewCallbacks) fragment);
Run Code Online (Sandbox Code Playgroud)

我不太喜欢这个解决方案,因为它用触摸包装覆盖了整个屏幕,因为它导致 viewPager 的过度绘制(并要求您为其设置背景),并且因为它与我的相比有点复杂心里。无论我如何使用滚动规则,它也比 Lollipop 的电话应用程序流畅得多。

我可以让 TouchInterceptionListener 开始处理触摸事件,前提是它们源自 RecyclerView,但这使得它的复杂性变得更糟。