android– 如何同步滚动的2个RecyclerViews的第一个位置?

android– 如何同步滚动的2个RecyclerViews的第一个位置?,第1张

概述背景我有2个RecyclerView实例.一个是水平的,第二个是垂直的.它们都显示相同的数据并且具有相同数量的项目,但是以不同的方式,并且单元格的大小不必相等.我希望滚动到一个将与另一个同步,以便在一个上显示的第一个项目将始终显示在另一个上(作为第一个).问题即使我成功地使它们

背景

我有2个RecyclerVIEw实例.一个是水平的,第二个是垂直的.

它们都显示相同的数据并且具有相同数量的项目,但是以不同的方式,并且单元格的大小不必相等.

我希望滚动到一个将与另一个同步,以便在一个上显示的第一个项目将始终显示在另一个上(作为第一个).

问题

即使我成功地使它们同步(我只选择哪一个是“主”,控制另一个的滚动),滚动的方向似乎影响它的工作方式.

假设片刻具有相同的高度:

如果我向上/向左滚动,它或多或少地按照我的意图工作:

但是,如果我向下/向右滚动,它会让其他RecyclerVIEw显示另一个的第一项,但通常不会作为第一项:

注意:在上面的截图中,我已经在底部的RecyclerVIEw中滚动,但是类似的结果将与顶部的一起.

如果像我写的那样,细胞有不同的大小,情况会变得更糟:

我试过的

我尝试使用其他滚动方式并转到其他位置,但所有尝试都失败了.

使用smoothScrollToposition使事情变得更糟(虽然它看起来确实更好),因为如果我扔掉,在某些时候,其他RecyclerVIEw控制我与之交互的那个.

我想我应该使用滚动的方向,以及其他RecyclerVIEw上当前显示的项目.

这是当前(示例)代码.请注意,在实际代码中,单元格可能没有相同的大小(有些是高,有些是短等等).代码中的一行使单元格具有不同的高度.

activity_main.xml中

<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.v7.Widget.RecyclerVIEw        androID:ID="@+ID/topReccyclerVIEw" androID:layout_wIDth="0dp" androID:layout_height="100dp"        androID:layout_marginEnd="8dp" androID:layout_marginStart="8dp" androID:layout_margintop="8dp"        androID:orIEntation="horizontal" app:layoutManager="androID.support.v7.Widget.linearlayoutmanager"        app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent"        app:layout_constrainttop_totopOf="parent" tools:Listitem="@layout/horizontal_cell"/>    <androID.support.v7.Widget.RecyclerVIEw        androID:ID="@+ID/bottomrecyclerVIEw" androID:layout_wIDth="0dp" androID:layout_height="0dp"        androID:layout_marginBottom="8dp" androID:layout_marginEnd="8dp" androID:layout_marginStart="8dp"        androID:layout_margintop="8dp" app:layoutManager="androID.support.v7.Widget.linearlayoutmanager"        app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent"        app:layout_constraintStart_toStartOf="parent" app:layout_constrainttop_toBottomOf="@+ID/topReccyclerVIEw"        tools:Listitem="@layout/horizontal_cell"/></androID.support.constraint.ConstraintLayout>

horizo​​ntal_cell.xml

<TextVIEw    androID:ID="@+ID/textVIEw" xmlns:androID="http://schemas.androID.com/apk/res/androID"    xmlns:tools="http://schemas.androID.com/tools" androID:layout_wIDth="100dp" androID:layout_height="100dp"    androID:gravity="center" tools:text="@tools:sample/lorem"/>

vertical_cell.xml

<TextVIEw    androID:ID="@+ID/textVIEw" xmlns:androID="http://schemas.androID.com/apk/res/androID"    xmlns:tools="http://schemas.androID.com/tools" androID:layout_wIDth="match_parent" androID:layout_height="50dp"    androID:gravity="center" tools:text="@tools:sample/lorem"/>

主要活动

class MainActivity : AppCompatActivity() {    var masterVIEw: VIEw? = null    overrIDe fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        setContentVIEw(R.layout.activity_main)        val inflater = LayoutInflater.from(this)        topReccyclerVIEw.adapter = object : RecyclerVIEw.Adapter<RecyclerVIEw.VIEwHolder>() {            overrIDe fun onBindVIEwHolder(holder: RecyclerVIEw.VIEwHolder, position: Int) {                (holder.itemVIEw as TextVIEw).text = position.toString()                holder.itemVIEw.setBackgroundcolor(if(position%2==0) 0xffff0000.toInt() else 0xff00ff00.toInt())            }            overrIDe fun getItemCount(): Int {                return 100            }            overrIDe fun onCreateVIEwHolder(parent: VIEwGroup?, vIEwType: Int): RecyclerVIEw.VIEwHolder {                return object : RecyclerVIEw.VIEwHolder(inflater.inflate(R.layout.horizontal_cell, parent, false)) {}            }        }        bottomrecyclerVIEw.adapter = object : RecyclerVIEw.Adapter<RecyclerVIEw.VIEwHolder>() {        val baseHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50f, resources.displayMetrics).toInt()            overrIDe fun onBindVIEwHolder(holder: RecyclerVIEw.VIEwHolder, position: Int) {                (holder.itemVIEw as TextVIEw).text = position.toString()                holder.itemVIEw.setBackgroundcolor(if(position%2==0) 0xffff0000.toInt() else 0xff00ff00.toInt())                // this makes the heights of the cells different from one another:                holder.itemVIEw.layoutParams.height = baseHeight + (if (position % 3 == 0) 0 else baseHeight / (position % 3))            }            overrIDe fun getItemCount(): Int {                return 100            }            overrIDe fun onCreateVIEwHolder(parent: VIEwGroup?, vIEwType: Int): RecyclerVIEw.VIEwHolder {                return object : RecyclerVIEw.VIEwHolder(inflater.inflate(R.layout.vertical_cell, parent, false)) {}            }        }        linearSnapHelper().attachToRecyclerVIEw(topReccyclerVIEw)        linearSnapHelper().attachToRecyclerVIEw(bottomrecyclerVIEw)        topReccyclerVIEw.addOnScrollListener(OnScrollListener(topReccyclerVIEw, bottomrecyclerVIEw))        bottomrecyclerVIEw.addOnScrollListener(OnScrollListener(bottomrecyclerVIEw, topReccyclerVIEw))    }    inner class OnScrollListener(private val thisRecyclerVIEw: RecyclerVIEw, private val otherRecyclerVIEw: RecyclerVIEw) : RecyclerVIEw.OnScrollListener() {        var lastItemPos: Int = Int.MIN_VALUE        val thisRecyclerVIEwID = resources.getResourceEntryname(thisRecyclerVIEw.ID)        overrIDe fun onScrollStateChanged(recyclerVIEw: RecyclerVIEw?, newState: Int) {            super.onScrollStateChanged(recyclerVIEw, newState)            Log.d("AppLog", "onScrollStateChanged:$thisRecyclerVIEwID $newState")            when (newState) {                RecyclerVIEw.SCRolL_STATE_DRAGGING -> if (masterVIEw == null) {                    Log.d("AppLog", "setting $thisRecyclerVIEwID to be master")                    masterVIEw = thisRecyclerVIEw                }                RecyclerVIEw.SCRolL_STATE_IDLE -> if (masterVIEw == thisRecyclerVIEw) {                    Log.d("AppLog", "resetting $thisRecyclerVIEwID from being master")                    masterVIEw = null                    lastItemPos = Int.MIN_VALUE                }            }        }        overrIDe fun onScrolled(recyclerVIEw: RecyclerVIEw?, dx: Int, dy: Int) {            super.onScrolled(recyclerVIEw, dx, dy)            if ((dx == 0 && dy == 0) || (masterVIEw != null && masterVIEw != thisRecyclerVIEw))                return            //            Log.d("AppLog", "onScrolled:$thisRecyclerVIEw $dx-$dy")            val currentItem = (thisRecyclerVIEw.layoutManager as linearlayoutmanager).findFirstCompletelyVisibleItemposition()            if (lastItemPos == currentItem)                return            lastItemPos = currentItem            otherRecyclerVIEw.scrollToposition(currentItem)//            otherRecyclerVIEw.smoothScrollToposition(currentItem)            Log.d("AppLog", "currentItem:" + currentItem)        }    }}

问题

>如何让其他RecycerVIEw始终拥有与当前控制的第一项相同的第一项?
>如何修改代码以支持平滑滚动,而不会导致突然让其他RecyclerVIEw成为控件的问题?

编辑:在更新这里的示例代码后,具有不同大小的单元格(因为最初更接近我所拥有的问题,如前所述),我注意到捕捉不起作用.

这就是我选择使用此库正确捕捉它的原因:

https://github.com/DevExchanges/SnappingRecyclerview

因此,我使用’GravitySnapHelper’代替linearSnapHelper.似乎工作得更好,但仍然有同步问题,并在滚动时触摸.

编辑:
我终于修复了所有同步问题,即使单元格大小不同,它也可以正常工作.

还有一些问题:

>如果您使用一个RecyclerVIEw,然后触摸另一个,它会有非常奇怪的滚动行为.可能滚动的方式比它应该更多.
>滚动不平滑(同步时和投掷时),因此看起来不太好.
>遗憾的是,由于捕捉(我实际上可能只需要顶级的RecyclerVIEw),它会导致另一个问题:底部的RecyclerVIEw可能部分显示最后一项(截图有100个项目),我无法滚动更多以显示它完全:

我甚至不认为底部的RecyclerVIEw应该是贴紧的,除非触顶了.可悲的是,这是我到目前为止所做的全部,没有同步问题.

在找到所有修复后,这是新代码:

class MainActivity : AppCompatActivity() {    var masterVIEw: VIEw? = null    overrIDe fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        setContentVIEw(R.layout.activity_main)        val inflater = LayoutInflater.from(this)        topReccyclerVIEw.adapter = object : RecyclerVIEw.Adapter<RecyclerVIEw.VIEwHolder>() {            overrIDe fun onBindVIEwHolder(holder: RecyclerVIEw.VIEwHolder, position: Int) {                (holder.itemVIEw as TextVIEw).text = position.toString()                holder.itemVIEw.setBackgroundcolor(if (position % 2 == 0) 0xffff0000.toInt() else 0xff00ff00.toInt())            }            overrIDe fun getItemCount(): Int = 1000            overrIDe fun onCreateVIEwHolder(parent: VIEwGroup?, vIEwType: Int): RecyclerVIEw.VIEwHolder {                return object : RecyclerVIEw.VIEwHolder(inflater.inflate(R.layout.horizontal_cell, parent, false)) {}            }        }        bottomrecyclerVIEw.adapter = object : RecyclerVIEw.Adapter<RecyclerVIEw.VIEwHolder>() {            val baseHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50f, resources.displayMetrics).toInt()            overrIDe fun onBindVIEwHolder(holder: RecyclerVIEw.VIEwHolder, position: Int) {                (holder.itemVIEw as TextVIEw).text = position.toString()                holder.itemVIEw.setBackgroundcolor(if (position % 2 == 0) 0xffff0000.toInt() else 0xff00ff00.toInt())                holder.itemVIEw.layoutParams.height = baseHeight + (if (position % 3 == 0) 0 else baseHeight / (position % 3))            }            overrIDe fun getItemCount(): Int = 1000            overrIDe fun onCreateVIEwHolder(parent: VIEwGroup?, vIEwType: Int): RecyclerVIEw.VIEwHolder {                return object : RecyclerVIEw.VIEwHolder(inflater.inflate(R.layout.vertical_cell, parent, false)) {}            }        }        // GravitySnapHelper is available from : https://github.com/DevExchanges/SnapPingRecyclervIEw        GravitySnapHelper(Gravity.START).attachToRecyclerVIEw(topReccyclerVIEw)        GravitySnapHelper(Gravity.top).attachToRecyclerVIEw(bottomrecyclerVIEw)        topReccyclerVIEw.addOnScrollListener(OnScrollListener(topReccyclerVIEw, bottomrecyclerVIEw))        bottomrecyclerVIEw.addOnScrollListener(OnScrollListener(bottomrecyclerVIEw, topReccyclerVIEw))    }    inner class OnScrollListener(private val thisRecyclerVIEw: RecyclerVIEw, private val otherRecyclerVIEw: RecyclerVIEw) : RecyclerVIEw.OnScrollListener() {        var lastItemPos: Int = Int.MIN_VALUE        val thisRecyclerVIEwID = resources.getResourceEntryname(thisRecyclerVIEw.ID)        overrIDe fun onScrollStateChanged(recyclerVIEw: RecyclerVIEw?, newState: Int) {            super.onScrollStateChanged(recyclerVIEw, newState)            when (newState) {                RecyclerVIEw.SCRolL_STATE_DRAGGING -> if (masterVIEw == null) {                    masterVIEw = thisRecyclerVIEw                }                RecyclerVIEw.SCRolL_STATE_IDLE -> if (masterVIEw == thisRecyclerVIEw) {                    masterVIEw = null                    lastItemPos = Int.MIN_VALUE                }            }        }        overrIDe fun onScrolled(recyclerVIEw: RecyclerVIEw?, dx: Int, dy: Int) {            super.onScrolled(recyclerVIEw, dx, dy)            if (dx == 0 && dy == 0 || masterVIEw !== null && masterVIEw !== thisRecyclerVIEw) {                return            }            val otherLayoutManager = otherRecyclerVIEw.layoutManager as linearlayoutmanager            val thisLayoutManager = thisRecyclerVIEw.layoutManager as linearlayoutmanager            val currentItem = thisLayoutManager.findFirstCompletelyVisibleItemposition()            if (lastItemPos == currentItem) {                return            }            lastItemPos = currentItem            otherLayoutManager.scrollTopositionWithOffset(currentItem, 0)        }    }}

解决方法:

结合两个RecyclerVIEws,有四种运动情况:

一种.将水平回收器向左滚动

湾向右滚动它

C.将垂直回收器滚动到顶部

d.将其滚动到底部

案例a和c不需要照顾,因为它们开箱即用.对于案例b和d,你需要做两件事:

>了解您所处的回收器(垂直或水平)以及滚动的方向(向上或向下,向左或向右)和
>根据otherRecyclerVIEw中可见项目的数量计算(列表项目的)偏移量(如果屏幕较大,则偏移量也需要更大).

弄清楚这个有点繁琐,但结果非常直接.

    @OverrIDe    public voID onScrollStateChanged(RecyclerVIEw recyclerVIEw, int newState) {        super.onScrollStateChanged(recyclerVIEw, newState);        if (newState == RecyclerVIEw.SCRolL_STATE_DRAGGING) {            if (masterVIEw == otherRecyclerVIEw) {                thisRecyclerVIEw.stopScroll();                otherRecyclerVIEw.stopScroll();                syncScroll(1, 1);            }            masterVIEw = thisRecyclerVIEw;        } else if (newState == RecyclerVIEw.SCRolL_STATE_IDLE && masterVIEw == thisRecyclerVIEw) {            masterVIEw = null;        }    }    @OverrIDe    public voID onScrolled(RecyclerVIEw recyclervIEw, int dx, int dy) {        super.onScrolled(recyclervIEw, dx, dy);        if ((dx == 0 && dy == 0) || (masterVIEw != null && masterVIEw != thisRecyclerVIEw)) {            return;        }        syncScroll(dx, dy);    }    voID syncScroll(int dx, int dy) {        linearlayoutmanager otherLayoutManager = (linearlayoutmanager) otherRecyclerVIEw.getLayoutManager();        linearlayoutmanager thisLayoutManager = (linearlayoutmanager) thisRecyclerVIEw.getLayoutManager();        int offset = 0;        if ((thisLayoutManager.getorIEntation() == HORIZONTAL && dx > 0) || (thisLayoutManager.getorIEntation() == VERTICAL && dy > 0)) {            // scrolling horizontal recycler to left or vertical recycler to bottom            offset = otherLayoutManager.findLastCompletelyVisibleItemposition() - otherLayoutManager.findFirstCompletelyVisibleItemposition();        }        int currentItem = thisLayoutManager.findFirstCompletelyVisibleItemposition();        otherLayoutManager.scrollTopositionWithOffset(currentItem, offset);    }

当然,您可以将两个if子句组合在一起,因为这些子句是相同的.为了便于阅读,我认为将它们分开是件好事.

第二个问题是当“第一”回收器仍在滚动时触及相应的“其他”回收器时同步.以下代码(包括在上面)是相关的:

if (newState == RecyclerVIEw.SCRolL_STATE_DRAGGING) {    if (masterVIEw == otherRecyclerVIEw) {        thisRecyclerVIEw.stopScroll();        otherRecyclerVIEw.stopScroll();        syncScroll(1, 1);    }    masterVIEw = thisRecyclerVIEw;}

触摸回收器并拖动一点时,newState等于SCRolL_STATE_DRAGGING.因此,如果在触摸相应的“其他”回收器之后触摸(并且拖动),则第二个条件(masterVIEw == otherRecyclervIEw)为真.然后停止两个回收器并且“其他”回收器与“此”回收器同步.

总结

以上是内存溢出为你收集整理的android – 如何同步滚动的2个RecyclerViews的第一个位置?全部内容,希望文章能够帮你解决android – 如何同步滚动的2个RecyclerViews的第一个位置?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/1097962.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-28
下一篇2022-05-28

发表评论

登录后才能评论

评论列表(0条)

    保存