首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >垂直回收视图和水平回收视图

垂直回收视图和水平回收视图
EN

Stack Overflow用户
提问于 2022-11-24 23:10:06
回答 3查看 120关注 0票数 1

我正在创建一个食品菜单布局,菜单有类别与项目。最上面是饮料、寿司等类别名称的列表,这是一个水平滚动的回收视图,底部是分类项目,例如饮料下面有cocacola芬达等,这是一个垂直滚动的回收视图。我试图同步这两个回收视图与一个行为,在其中当你滚动垂直,它滚动水平,反之亦然。

我创建这个类是为了实现这个特性。

代码语言:javascript
运行
复制
import android.graphics.Typeface
import android.os.Handler
import android.os.Looper
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.LinearSmoothScroller
import androidx.recyclerview.widget.RecyclerView

class TwoRecyclerViews(
    private val recyclerViewHorizontal: RecyclerView,
    private val recyclerViewVertical: RecyclerView,
    private var indices: List<Int>,
    private var isSmoothScroll: Boolean = false,
) {

private var attached = false

private var horizontalRecyclerState = RecyclerView.SCROLL_STATE_IDLE
private var verticalRecyclerState = RecyclerView.SCROLL_STATE_IDLE


private val smoothScrollerVertical: RecyclerView.SmoothScroller =
    object : LinearSmoothScroller(recyclerViewVertical.context) {
        override fun getVerticalSnapPreference(): Int {
            return SNAP_TO_START
        }
    }


fun attach() {
    recyclerViewHorizontal.adapter
        ?: throw RuntimeException("Cannot attach with no Adapter provided to RecyclerView")

    recyclerViewVertical.adapter
        ?: throw RuntimeException("Cannot attach with no Adapter provided to RecyclerView")

    updateFirstPosition()
    notifyIndicesChanged()
    attached = true
}

private fun detach() {
    recyclerViewVertical.clearOnScrollListeners()
    recyclerViewHorizontal.clearOnScrollListeners()
}

fun reAttach() {
    detach()
    attach()
}

private fun updateFirstPosition() {
    Handler(Looper.getMainLooper()).postDelayed({
        val view = recyclerViewHorizontal.findViewHolderForLayoutPosition(0)?.itemView
        val textView = view?.findViewById<TextView>(R.id.horizontalCategoryName)
        val imageView = view?.findViewById<ImageView>(R.id.categorySelectionIndicator)
        imageView?.visibility = View.VISIBLE
        textView?.setTypeface(null, Typeface.BOLD)
        textView?.setTextColor(recyclerViewVertical.context.getColor(R.color.primary_1))
    }, 100)
}

fun isAttached() = attached

private fun notifyIndicesChanged() {
    recyclerViewHorizontal.addOnScrollListener(onHorizontalScrollListener)
    recyclerViewVertical.addOnScrollListener(onVerticalScrollListener)
}

private val onHorizontalScrollListener = object : RecyclerView.OnScrollListener() {
    override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
        horizontalRecyclerState = newState
    }

    override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
        super.onScrolled(recyclerView, dx, dy)

        val linearLayoutManager: LinearLayoutManager =
            recyclerView.layoutManager as LinearLayoutManager?
                ?: throw RuntimeException("No LinearLayoutManager attached to the RecyclerView.")

        var itemPosition =
            linearLayoutManager.findFirstCompletelyVisibleItemPosition()

        if (itemPosition == -1) {
            itemPosition =
                linearLayoutManager.findFirstVisibleItemPosition()
        }

        if (horizontalRecyclerState == RecyclerView.SCROLL_STATE_DRAGGING ||
            horizontalRecyclerState == RecyclerView.SCROLL_STATE_SETTLING
        ) {
            for (position in indices.indices) {
                val view = recyclerView.findViewHolderForLayoutPosition(indices[position])?.itemView
                val textView = view?.findViewById<TextView>(R.id.horizontalCategoryName)
                val imageView = view?.findViewById<ImageView>(R.id.categorySelectionIndicator)
                if (itemPosition == indices[position]) {
                    if (isSmoothScroll) {
                        smoothScrollerVertical.targetPosition = indices[position]
                        recyclerViewVertical.layoutManager?.startSmoothScroll(smoothScrollerVertical)
                    } else {
                        (recyclerViewVertical.layoutManager as LinearLayoutManager?)?.scrollToPositionWithOffset(
                            indices[position], 16.dpToPx()
                        )
                    }
                    imageView?.visibility = View.VISIBLE
                    textView?.setTypeface(null, Typeface.BOLD)
                    textView?.setTextColor(recyclerView.context.getColor(R.color.primary_1))
                } else {
                    imageView?.visibility = View.GONE
                    textView?.setTypeface(null, Typeface.NORMAL)
                    textView?.setTextColor(recyclerView.context.getColor(R.color.secondary_5))
                }
            }
        }
    }
}

private val onVerticalScrollListener = object : RecyclerView.OnScrollListener() {
    override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
        verticalRecyclerState = newState
    }

    override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
        super.onScrolled(recyclerView, dx, dy)

        val linearLayoutManager: LinearLayoutManager =
            recyclerView.layoutManager as LinearLayoutManager?
                ?: throw RuntimeException("No LinearLayoutManager attached to the RecyclerView.")

        var itemPosition =
            linearLayoutManager.findFirstCompletelyVisibleItemPosition()

        if (itemPosition == -1) {
            itemPosition =
                linearLayoutManager.findFirstVisibleItemPosition()
        }

        if (verticalRecyclerState == RecyclerView.SCROLL_STATE_DRAGGING ||
            verticalRecyclerState == RecyclerView.SCROLL_STATE_SETTLING
        ) {
            for (position in indices.indices) {
                val view = recyclerViewHorizontal.findViewHolderForAdapterPosition(indices[position])?.itemView
                val textView = view?.findViewById<TextView>(R.id.horizontalCategoryName)
                val imageView = view?.findViewById<ImageView>(R.id.categorySelectionIndicator)
                if (itemPosition == indices[position]) {
                    (recyclerViewHorizontal.layoutManager as LinearLayoutManager?)?.scrollToPositionWithOffset(
                        indices[position], 16.dpToPx()
                    )
                    imageView?.visibility = View.VISIBLE
                    textView?.setTypeface(null, Typeface.BOLD)
                    textView?.setTextColor(recyclerViewVertical.context.getColor(R.color.primary_1))
                } else {
                    imageView?.visibility = View.GONE
                    textView?.setTypeface(null, Typeface.NORMAL)
                    textView?.setTextColor(recyclerViewVertical.context.getColor(R.color.secondary_5))
                }
            }
        }
    }
}


}

这个类对于垂直滚动很好,但是水平滚动是不稳定的。如果您还有一个比我创建的类更好的解决方案,请分享。

EN

回答 3

Stack Overflow用户

发布于 2022-12-02 07:20:40

要解决TwoRecyclerViews类的问题,可以尝试以下方法:

  1. 在两个RecyclerViews上使用addOnItemTouchListener()而不是addOnScrollListener(),因为当用户抛出RecyclerView时addOnScrollListener()不会被调用。

私人娱乐recyclerViewHorizontal.addOnItemTouchListener(onHorizontalScrollListener) notifyIndicesChanged() { recyclerViewVertical.addOnItemTouchListener(onVerticalScrollListener) }

  1. 使用findFirstVisibleItemPosition()而不是findFirstCompletelyVisibleItemPosition()来获取RecyclerViews中的当前项位置,因为如果没有完全可见的项,findFirstCompletelyVisibleItemPosition()将返回-1。

var itemPosition =itemPosition

  1. 使用itemPosition变量获取RecyclerView中的当前项,然后使用索引列表在其他RecyclerView中获取相应的索引。

//获取linearLayoutManager.findViewByPosition(itemPosition) val currentItem = RecyclerView //中的当前项,使用索引列表在其他RecyclerView val索引= indicesitemPosition中获取相应的索引

  1. 使用索引变量将其他RecyclerView滚动到正确位置。

//滚动另一个RecyclerView到正确的位置val otherLinearLayoutManager =RecyclerView

票数 0
EN

Stack Overflow用户

发布于 2022-12-02 17:23:00

实现UI/UX要求的最佳方法是使用带有垂直回收器视图的TabLayout

可以将回收器视图中的列表项目和选项卡布局中的选项卡设置为动态的项目/选项卡数。

当您上下滚动并到达相应的类别时,请使用以下代码更新选项卡布局。属性中的每个类别。

代码语言:javascript
运行
复制
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs); // Once for the Activity of Fragment
TabLayout.Tab tab = tabLayout.getTabAt(someIndex); // Some index should be obtain from the dataset 
tab.select();

同样,当单击选项卡或滚动选项卡布局时,相应地更新RecyclerVew。

代码语言:javascript
运行
复制
recyclerView.smoothScrollToPosition(itemCount)

希望这会有帮助,干杯!

票数 0
EN

Stack Overflow用户

发布于 2022-12-03 18:44:52

看起来,水平滚动的问题是它只滚动到垂直RecyclerView中的第一项,而不是滚动到在水平RecyclerView中滚动到的类别的相应项。要解决这个问题,可以使用LinearLayoutManager.scrollToPositionWithOffset()方法滚动到垂直RecyclerView中的对应项。

下面是如何更新onHorizontalScrollListener以使用此方法的示例:

代码语言:javascript
运行
复制
private val onHorizontalScrollListener = object : RecyclerView.OnScrollListener() {
    override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
        horizontalRecyclerState = newState
    }

    override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
        super.onScrolled(recyclerView, dx, dy)

        val linearLayoutManager: LinearLayoutManager =
            recyclerView.layoutManager as LinearLayoutManager?
                ?: throw RuntimeException("No LinearLayoutManager attached to the RecyclerView.")

        var itemPosition =
            linearLayoutManager.findFirstCompletelyVisibleItemPosition()

        if (itemPosition == -1) {
            itemPosition =
                linearLayoutManager.findFirstVisibleItemPosition()
        }

        if (horizontalRecyclerState == RecyclerView.SCROLL_STATE_DRAGGING ||
            horizontalRecyclerState == RecyclerView.SCROLL_STATE_SETTLING
        ) {
            if (indices.size > itemPosition) {
                val index = indices[itemPosition]
                if (isSmoothScroll) {
                    smoothScrollerVertical.targetPosition = index
                    recyclerViewVertical.layoutManager?.startSmoothScroll(smoothScrollerVertical)
                } else {
                    // Use the LinearLayoutManager.scrollToPositionWithOffset() method to scroll to the corresponding item in the vertical RecyclerView
                    recyclerViewVertical.layoutManager?.scrollToPositionWithOffset(index, 0)
                }
            }
        }
    }
}

请注意,此解决方案假定indices列表包含垂直RecyclerView中水平RecyclerView中每个类别对应项的索引。您需要确保使用正确的索引正确填充此列表。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74567007

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档