我的目标是可以将当前选定的项目放在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>
最终结果看起来和我想要的方式一样。
但是当我通过覆盖LinearLayoutManager
这样禁用滚动时:
public class TestLayoutManager extends LinearLayoutManager {
public TestLayoutManager(Context context) {
super(context, VERTICAL, false);
}
@Override
public boolean canScrollVertically() {
return false;
}
}
我得到的项目呈现不正确:
正如我所注意到的,这个高度等于
itemHeight = recyclerViewHeight - (TopPaddding + BottomPadding)
因为当我在RecyclerView上设置clipToPadding=true
时,我得到了这样的观点:
物品的高度以相同的方式切割。
是否有可能以某种方式使其工作?
答案 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
滚动的可接受方式。我认为当填充比通常情况下的屏幕尺寸小得多时会起作用,但是当填充超出可用空间时会失败。