水平 RecyclerView 内的水平 RecyclerView
Posted
技术标签:
【中文标题】水平 RecyclerView 内的水平 RecyclerView【英文标题】:Horizontal RecyclerView inside a Horizontal RecyclerView 【发布时间】:2019-01-20 00:48:31 【问题描述】:我正在尝试在另一个带有水平 LinearLayoutManager 的 RecyclerView 中使用带有水平 LinearLayoutManager 的 RecyclerView。整个层次结构是这样的:RecyclerView,Recycler的child是一个ScrollView,它包含一个TextView和另一个RecyclerView。为了更好地理解,我希望第一个回收器像 ViewPager 一样工作,但不完全相同(我不想使用 ViewPager)。问题是当我尝试在子回收器上水平滚动时,运动事件被父回收器捕获,导致滚动到下一页而无法滚动子回收器。
MainActivityLayout:
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_
android:layout_
tools:context=".MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/RVpage"
android:descendantFocusability="blocksDescendants"
android:focusableInTouchMode="false"
android:focusable="false"
android:layout_
android:layout_ />
</LinearLayout>
MainActivity.java:
public class MainActivity extends AppCompatActivity
private RecyclerView recyclerView;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setRecycler();
private void setRecycler()
recyclerView=(RecyclerView) findViewById(R.id.RVpage);
SnapHelper snapHelper = new LinearSnapHelper();
snapHelper.attachToRecyclerView(recyclerView);
BigRecyclerAdapter bigRecyclerAdapter=new BigRecyclerAdapter(this);
recyclerView.setAdapter(bigRecyclerAdapter);
//recyclerView.setNestedScrollingEnabled(true);
recyclerView.setLayoutManager(new LinearLayoutManager(
this, LinearLayoutManager.HORIZONTAL, false)
);
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener()
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState)
//Toast.makeText(MainActivity.this, "CHANGED BIG", Toast.LENGTH_SHORT).show();
super.onScrollStateChanged(recyclerView, newState);
);
PageRecycler 布局:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_
android:layout_
android:orientation="vertical">
<LinearLayout
android:layout_
android:layout_
android:orientation="vertical">
<TextView
android:layout_
android:layout_
android:layout_margin="20dp"
android:text="nskjdnaskdn \n sudbadbak
\n sudbadbak
\n sudbadbak
\n sudbadbak
\n sudbadbak\n sudbadbak
v
\n sudbadbak
\n sudbadbak
\n sudbadbak
\n sudbadbak
\n sudbadbak
\n sudbadbak
\n sudbadbak
\n sudbadbak
v
v
\n sudbadbak
\n sudbadbak
v
v
\n sudbadbak
vv
\n sudbadbak
v
v
\n sudbadbak"
android:textColor="@android:color/black"
android:textSize="50sp"/>
<android.support.v7.widget.RecyclerView
android:id="@+id/photo"
android:layout_
android:layout_
android:clickable="true"
android:focusableInTouchMode="true"
android:focusedByDefault="true"
android:descendantFocusability="afterDescendents"
android:focusable="true"
android:padding="20dp" />
</LinearLayout>
</ScrollView>
在 relativeLayout 中我留下了我尝试过的所有东西,从 clickable=true 到 descendentFocusability。
PageRecycler 适配器:
class BigRecyclerAdapter(private val context: MainActivity) : RecyclerView.Adapter<BigRecyclerAdapter.ViewHolder>()
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder
val v = LayoutInflater.from(parent?.context)
.inflate(R.layout.raw, parent, false)
return ViewHolder(v)
/* override fun onViewAttachedToWindow(holder: ViewHolder?)
var parent = holder?.recycler?.parent
val DEBUG_TAG_SCROLL = "DEBUG_TAG_SCROLL"
Log.d(DEBUG_TAG_SCROLL, "NESTED_SCROLL_VALUE: $holder?.recycler?.hasNestedScrollingParent()")
if (holder?.recycler?.parent is RecyclerView)
Log.d(DEBUG_TAG_SCROLL, "Good parent")
super.onViewAttachedToWindow(holder)
*/
override fun getItemCount(): Int
return 5
override fun onBindViewHolder(holder: ViewHolder?, position: Int)
holder?.bind()
// val DEBUG_TAG_SCROLL = "DEBUG_TAG_SCROLL"
//// Log.d(DEBUG_TAG_SCROLL, "NESTED_SCROLL_VALUE: $holder?.recycler?.hasNestedScrollingParent()")
//
// if(holder?.recycler?.parent is RecyclerView)
// Log.d(DEBUG_TAG_SCROLL, "Good parent")
//
inner class ViewHolder(v: View) : RecyclerView.ViewHolder(v)
var recycler: RecyclerView
init
recycler = v.findViewById(R.id.photo) as RecyclerView
fun bind()
recycler.addOnScrollListener(object : RecyclerView.OnScrollListener()
override fun onScrollStateChanged(recyclerView: RecyclerView?, newState: Int)
Toast.makeText(context, "CHANGED SMALL", Toast.LENGTH_SHORT).show()
super.onScrollStateChanged(recyclerView, newState)
// override fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int)
// super.onScrolled(recyclerView, dx, dy)
//
)
val smallRecyclerAdapter = SmallRecyclerAdapter(context)
recycler.adapter = smallRecyclerAdapter
recycler.layoutManager = LinearLayoutManager(
context, LinearLayoutManager.HORIZONTAL, false
)
recycler.scrollToPosition(5)
PhotoRecycler raw(子recyclerView):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_>
<ImageView
android:layout_
android:layout_
android:id="@+id/photoView"/>
</LinearLayout>
PhotoRecycler 适配器:
class SmallRecyclerAdapter(private val context: MainActivity): RecyclerView.Adapter<SmallRecyclerAdapter.ViewHolder>()
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder
val v = LayoutInflater.from(parent?.context)
.inflate(R.layout.raw_small, parent, false)
// set the view's size, margins, paddings and layout parameters
return ViewHolder(v)
override fun getItemCount(): Int
return 10
override fun onBindViewHolder(holder: ViewHolder?, position: Int)
//TODO here
var drawableName="p"+((position%4)+1)
val drawable = context.getResources().getDrawable(context.getResources()
.getIdentifier(drawableName, "drawable", context.getPackageName()))
holder?.imageView?.setImageDrawable(drawable)
inner class ViewHolder(v: View) : RecyclerView.ViewHolder(v)
var imageView: ImageView
init
imageView=v.findViewById(R.id.photoView) as ImageView
如果您需要更多详细信息,请告诉我,我会更新。
【问题讨论】:
你为什么要这个?在同一方向上的嵌套滚动通常会出现问题。应用程序应该如何知道它应该滚动哪个元素? 为什么要问问题?它应该基本上可以工作,它可以与 ViewPager 一起工作,并且是相同的想法。我猜它知道在水平回收器内滚动垂直回收器的方式相同。我可以通过扩展 Recycler 或 LayoutManager 让它在很长一段时间内工作,但它是矫枉过正的。在尝试之前我想我应该问一下是否存在更简单的解决方案 它知道在水平回收器中滚动垂直回收器 - 这很容易区分,因为它的滚动方向不同。我的 2 美分是更简单的解决方案是制作不需要嵌套水平滚动的不同设计 设计不是我可以改变的。容易或不区分它应该。它只是一个滚动监听器,应该传播到视图的子视图 如果滚动事件传播给孩子会发生什么?他们都滚动?还是只有孩子?只有父母?它是怎么知道的 【参考方案1】:之前我实现了一个嵌套的ScrollView,我以为子滚动视图总是在消耗触摸,而父滚动视图永远不会听他们的
方法的作用来了
onInterceptTouchEvent
控制视图是使用触摸还是将其传递给其父级。
所以计划是计算滚动的方向,我是否到达了子 ScrollView 的滚动结束。
此代码是 2 年前编写的,因此如果不推荐使用,请原谅。
public class CustomScrollView extends ScrollView
private boolean bottomReached = false;
private boolean topReached = true;
private float startTouch = -1;
private float distance = -1;
public CustomScrollView(Context context)
super(context);
public CustomScrollView(Context context, AttributeSet attrs)
super(context, attrs);
public CustomScrollView(Context context, AttributeSet attrs, int defStyleAttr)
super(context, attrs, defStyleAttr);
@Override
protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY)
super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
@Override
public boolean onInterceptTouchEvent(MotionEvent ev)
switch (ev.getAction())
case MotionEvent.ACTION_DOWN:
startTouch = ev.getY();
break;
case MotionEvent.ACTION_UP:
startTouch = -1;
break;
case MotionEvent.ACTION_MOVE:
distance = ev.getY() - startTouch;
if (Math.abs(distance) < 10)
boolean onIntercept = super.onInterceptTouchEvent(ev);
return onIntercept;
else
if (!bottomReached && !topReached)
return true;
else
if (distance > 0)
// Scrolling Up
return bottomReached;
else
// Scrolling Down
return topReached;
return super.onInterceptTouchEvent(ev);
@Override
public boolean onTouchEvent(MotionEvent ev)
switch (ev.getAction())
case MotionEvent.ACTION_DOWN:
startTouch = ev.getY();
break;
case MotionEvent.ACTION_UP:
startTouch = -1;
break;
case MotionEvent.ACTION_MOVE:
distance = ev.getY() - startTouch;
return super.onTouchEvent(ev);
【讨论】:
【参考方案2】:看看这个网站和他在 GitHub 上的代码 Nested Recyclerview
【讨论】:
以上是关于水平 RecyclerView 内的水平 RecyclerView的主要内容,如果未能解决你的问题,请参考以下文章
Android 布局:具有滚动行为的 Viewpager 内的垂直 Recyclerview 内的水平 Recyclerview
NestedScrollView 内的 RecyclerView :使水平滚动更容易
垂直 RecyclerView 内的水平 ViewPager2
如何修复垂直 RecyclerView 内的水平 ViewPager2 和 RecyclerView 的滚动问题?