滚动禁用时,RecyclerView项目的高度不正确

时间:2017-02-21 16:20:55

标签: android android-recyclerview

我的目标是可以将当前选定的项目放在RecyclerView的中心,同时禁用用户滚动的功能(我只想通过我的代码执行此操作)。

为此,我添加了大的顶部和底部填充,因此我可以将第一个和最后一个项目滚动到中心(垂直)。我还添加了clipToPadding="false"以使滚动工作如上所述。

<android.support.v7.widget.RecyclerView
    android:id="@+id/playRecyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingTop="290dp"
    android:paddingBottom="290dp"
    android:clipToPadding="false"/>

290的值只是一个示例,它当然应根据屏幕大小而有所不同。 我用以下代码隔离了我的问题:

活动是最简单的(唯一的方法):

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.recycler_activity);

    recyclerView = (RecyclerView) findViewById(R.id.playRecyclerView);
    adapter = new TestAdapter();
    recyclerView.setLayoutManager(linearLayoutManager);
    recyclerView.setAdapter(adapter);
}

TestAdapter也非常简单,实际上可能并不重要,所以我会跳过这段代码。

项目的布局xml是RelativeLayout,其中包含TextView

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:background="@drawable/list_item_bg">

    <TextView
        android:id="@+id/taskListItem_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_margin="@dimen/fab_margin"
        android:textAppearance="?attr/textAppearanceListItem"
        android:textColor="@color/colorPrimary"
        android:textSize="20sp" />
</RelativeLayout>

最终结果看起来和我想要的方式一样。

enter image description here

但是当我通过覆盖LinearLayoutManager这样禁用滚动时:

public class TestLayoutManager extends LinearLayoutManager {

    public TestLayoutManager(Context context) {
        super(context, VERTICAL, false);
    }

    @Override
    public boolean canScrollVertically() {
        return false;
    }
}

我得到的项目呈现不正确:

enter image description here

正如我所注意到的,这个高度等于

itemHeight =  recyclerViewHeight - (TopPaddding + BottomPadding) 

因为当我在RecyclerView上设置clipToPadding=true时,我得到了这样的观点:

enter image description here

物品的高度以相同的方式切割。

是否有可能以某种方式使其工作?

2 个答案:

答案 0 :(得分:2)

通过重写onLayoutChildren来检测布局开始,并通过onLayoutCompleted来检测布局完成来解决代码的高度问题。

public class ScrollBlockingLayoutManager extends LinearLayoutManager {
    private boolean isInLayout = false;

    public ScrollBlockingLayoutManager(Context context) {
        super(context);
    }

    @Override
    public boolean canScrollVertically() {
        //Similarly you can customize "canScrollHorizontally()" for managing horizontal scroll
        return isInLayout || (mAdapter.scrollEnabled && super.canScrollVertically());
    }

    @Override
    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
        Log.e(TAG, "onLayoutChildren" + state.toString());
        isInLayout = true;
        super.onLayoutChildren(recycler, state);

    }

    @Override
    public void onLayoutCompleted(RecyclerView.State state) {
        super.onLayoutCompleted(state);
        Log.e(TAG, "onLayoutCompleted" + state.toString());
        isInLayout = false;

        //mCanScroll = false;
    }
}

答案 1 :(得分:1)

更新:添加了替代方法。

我的猜测是clipToPadding=false通过使RecyclerView不可滚动而被否定。请尝试以下操作以允许正确的布局并在最后禁用滚动。如果我理解你想要做什么,这应该有用。

public class TestLayoutManager extends LinearLayoutManager {
    boolean mCanScroll = true;

    public TestLayoutManager(Context context) {
        super(context, VERTICAL, false);
    }

    @Override
    public boolean canScrollVertically() {
        return super.canScrollVertically() && mCanScroll;
    }

    @Override
    public void onLayoutCompleted(RecyclerView.State state) {
        super.onLayoutCompleted(state);
        mCanScroll = false;
    }
}

上述方法适用于API 24但不适用于23,并且可能不适用于API&lt; 23(请参阅注释)。以下概述了替代方法。

RecyclerView代码使您失去clipToPadding=false的效果。这是因为RecyclerView被视为不可滚动的,并且在确定项目布局的最大尺寸时,填充是有道理的,因为填充与屏幕尺寸相比是如此之大。 (int size = Math.max(0, parentSize - padding)中的getChildMeasureSpec())。请参阅here

解决此问题的一种方法是将项目布局中的RelativeLayout设置为固定数量,如果您知道或可以确定它应该是什么 - 在填充之前应该遵循此固定数量。

另一种方法是翻转方法让布局管理器将RecyclerView视为可滚动,以便RecyclerView按预期布局。要禁止滚动,请在拦截触摸事件的RecyclerView上添加透明覆盖。此叠加层可以设置为visibility="gone"以再次启用滚动。

canScrollVertically()的响应设置为false似乎是阻止RecyclerView滚动的可接受方式。我认为当填充比通常情况下的屏幕尺寸小得多时会起作用,但是当填充超出可用空间时会失败。