无工具栏情况下滚动折叠视图

10

我正在制作一个与最近Android状态栏类似的布局。

输入图像描述

容器内有两个视图:ViewPagerRecyclerView。默认行为是当我滚动RecyclerView时,我希望ViewPager减小尺寸,反之亦然。

输入图像描述

逻辑:

viewPagerMaxHeight = 200;
if scrollTop
  is ViewPager.height > viewPagerMaxHeight?
    YES: Prevent Scroll and Decrease ViewPager size apropriatry
    No: Scroll RecyclerView
if scrollBottom
  did we scroll to position 0?
    YES: Start increasing ViewPager size
    No: Scroll RecyclerView

注意事项: - RecyclerView 包含不同大小的项目。 - 有时候会删除和添加项目。 - 这是一个简单的 RecyclerView,不像在通知中那样它们会相互折叠。

我可以自己构建大部分逻辑,但我无法为 RecyclerView 制作一个合适的监听器,让它返回滚动的方向和量。 防止 RecyclerView 滚动是一个额外的奖励。

编辑:

我已经在github上制作了一个示例。

v.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() {
    @Override
    public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
        Log.e("scrollY", ""+scrollY);
        Log.e("oldScrollY", ""+oldScrollY);
        Log.e("currentHeight", ""+currentHeight);
        if(scrollY == 200) {
            Log.e("==200", "JU");
        } else if (scrollY < 200) {
            Log.e("<200", ""+currentHeight);

            if(currentHeight < fullHeight) {
                Log.e("current<full", Integer.toString(deltaScroll));
                deltaScroll = oldScrollY - scrollY;
                currentHeight = currentHeight + deltaScroll;
                if(currentHeight > fullHeight) {
                    currentHeight = fullHeight;
                }
                ku.getLayoutParams().height = currentHeight;
                ku.requestLayout();
            }
            v.scrollTo(0, 200);
        } else if (scrollY > oldScrollY) {
            Log.e("Scroll DOWN", "" + Integer.toString(scrollY));
            deltaScroll = scrollY - oldScrollY;
            currentHeight = currentHeight - deltaScroll;
            if(currentHeight > minHeight) {
                ku.getLayoutParams().height = currentHeight;
                ku.requestLayout();
                v.scrollTo(0, 200);

            } else {
                currentHeight = minHeight;
                ku.getLayoutParams().height = minHeight;
                ku.requestLayout();
            }

        }
    }
});

我正在为RecycleView设置内边距,并将NestedScrollView滚动到第一个项目,以便内边距不可见。这使我即使在已经到达顶部时也能向上滚动。

一切似乎都正常,但是您会注意到,当缓慢滚动时,滚动会出现“抖动”(如果滚动得足够快,则不会发生)。 我的猜测是因为NestedScrollView本身会改变高度,例如向上滚动时也会发生向下滚动。


1
将RecyclerView和NestedScrollView混合使用通常会导致“跳跃”性能问题。您能否详细说明您正在使用ViewPager做什么?如果可能的话,请分享您的布局XML.... - Abhishek
1
查看协调布局。 - Rainmaker
@AbhishekSingh,有一个GitHub包含了我所有的视图。 - CBeTJlu4ok
3个回答

3
根据您当前的代码:
一切似乎都正常,但是当缓慢滚动时,您会注意到滚动是“跳跃”的...
是的,这是因为当用户缓慢滚动时(由于系统误将其解释为滚动==>停止==>滚动==>停止==>滚动==>停止==>...),方法onScrollChange可能会被调用多次,因此方法内部的逻辑将被执行多次或/和全部执行,而且由于有计算和逻辑(if和else),这可能会影响UI的响应性。如果用户快速滚动,则不会发生这种情况,它可能只会被调用一次,解释为单个滚动。
解决方案:
  1. 尽可能减少代码中的一些繁琐计算和逻辑。
  2. 在根布局中使用 Coordinator Layout 而不是 LinearLayout,并设置一些 Behaviours 以使子 ViewsCoordinatorLayout 内跟随。否则,可以使用一个 boolean 准备逻辑,确保方法 onSrollChange 的内容只会在用户最终完成整个缓慢滚动时被调用一次,而不是多次。

我无法使用CoordinatorLayout或ConstraintLayout。调用数量不是问题。我认为你没有花时间检查我的代码。 - CBeTJlu4ok
我已经阅读了你的代码,甚至在Github上。问题在于某个方法被调用了很多次!为什么不尝试使用动画,只有在前一个动画完成后才会加载,并且任何动画更新都将在前一个动画完成后保存。这也是用户友好的! - Xenolion
听起来像个好主意,既然这里没有太多时间来颁发赏金,那就请看这里。 - CBeTJlu4ok
哦,谢谢!祝你编程愉快!这是我第一次回答有赏金的问题! - Xenolion

2
以上内容可以通过ConstraintLayoutGuideline的帮助轻松实现。因此,当您向上滚动时,将指南线以编程方式设置为最小值,而当您向下滚动时,将指南线恢复正常状态。
以下是相同内容的xml示例。
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <android.support.constraint.Guideline
        android:id="@+id/viewPagerTopGuideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.1" />


    <android.support.constraint.Guideline
        android:id="@+id/viewPagerBottomGuideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.5" />

    <android.support.v4.view.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toTopOf="@+id/viewPagerBottomGuideline"
        app:layout_constraintTop_toBottomOf="@+id/viewPagerTopGuideline">

    </android.support.v4.view.ViewPager>

    <android.support.v7.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/viewPagerBottomGuideline"/>

</android.support.constraint.ConstraintLayout>

您也可以将视图放在NestedScrollView中。然后,您可以像这样设置指南:

 @BindView(R.id.viewPagerBottomGuideline)
Guideline guideLine;//have Used ButterKnife

ConstraintLayout.LayoutParams params = (ConstraintLayout.LayoutParams) guideLine.getLayoutParams();
            params.guidePercent = 0.20f; // 45% // range: 0 <-> 1
            guideLine.setLayoutParams(params);

我刚刚实现了滚动向上的功能,现在您需要将同样的功能实现到向下滚动中。


我无法使用CoordinatorLayout或ConstraintLayout。 - CBeTJlu4ok
虽然我不能使用它,但这是一个正确的答案。 - CBeTJlu4ok

1

虽然这个链接可能回答了问题,但请在此处提供实质性的部分。 - Dipali Shah
我无法使用 CoordinatorLayout 或 ConstraintLayout。 - CBeTJlu4ok

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接