如何在 RecyclerView 中使用具有动态位置的 RecyclerView 的 smoothScrollToPosition 进行滚动?
How to scroll with smoothScrollToPosition of RecyclerView with dynamic position in recyclerview?
我使用 tabLayout 作为 header 用于 recyclerView 适配器。滚动到 recyclerview 项目的静态位置没有问题。例如比萨的位置 2 header.tab 比萨的位置为零。
override fun onTabSelected(tab: TabLayout.Tab?) {
if (tab.position == 0)
recyclerview.smoothScrollToPosition(2)}
问题是我不知道如何滚动到某些 headers 我没有位置的项目的位置。据我所知,我可以获得所有项目位置,直到它们通过 onBindViewHolder 函数在屏幕上可见。正确的。
但是当所有项目都不可见或者我在列表的第一个时,我怎么能得到 headers 的其余位置?例如 drinks header 位置在列表的末尾,当用户单击 drink 选项卡时我需要知道位置。看来不是什么好办法。
我的情况是,我有一个 recyclerview 适配器。它有两种项目类型。
1-Header 项类型(食物类型如:三明治 - 披萨 - ...)
2 项类型(食物如:那不勒斯披萨 - 芝加哥披萨 - ...)
我的方法是:我创建一个哈希图。试图用 Header 项填充它。 <姓名,职位>。
我在onbindviewholder里面填的。正如我之前描述的那样。所有 header 项目的位置不会立即计算,直到我滚动所有列表以结束。所以 returnPositionHedaer 函数总是 return 0.
RecyclerViewAdapter Class:
class RecyclerAdapterInside( PlaceId:String?=null, var myReceivedData: List<ItemClass>?=null, val context:Context, private val ButtonFinish:RecyclerAdapterInsideButtonFinishCallback):RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var allHeader:HashMap<String,Int> = hashMapOf()
companion object {
const val Type_Header = 1
const val Type_Item = 2
}
private inner class CategoryViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var message: TextView = itemView.findViewById(R.id.textViewCategory)
fun bind(position: Int)
{
Log.d("inner Category","it is in CategoryViewHolder Header")
message.text = myReceivedData?.get(position)?.name
allHeader.put(message.text.toString(),position)
Log.d("itemss iewHolder",allHeader.keys.toString())
}
}
private inner class ItemViewholder(itemview: View) : RecyclerView.ViewHolder(itemview) {
val Name = itemview.findViewById(R.id.ItemName) as TextView
val Price = itemview.findViewById(R.id.ItemPrice) as TextView
val Category = itemview.findViewById(R.id.ItemCategory) as TextView
val Image = itemView.findViewById(R.id.ImgInsideMenu) as ImageView
val BtnAdd = itemView.findViewById(R.id.AddBtn) as Button
var count = itemview.findViewById(R.id.showCounter) as TextView
val BtnMin = itemView.findViewById(R.id.MinBtn) as Button
fun bind(position: Int) {
Log.d("value name is","${Name.text}")
Log.d("inner Category","it is in ItemViewHolder Header")
Name.text = myReceivedData!![position].name
Price.text = "Price :" + myReceivedData!![position].price
...
}
override fun getItemViewType(position: Int): Int {
return when (myReceivedData!!.get(position).getviewType()) {
1 -> Type_Header
2 -> Type_Item
else -> -1
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
if (viewType == Type_Header)
{
Log.d("OncreateViewHolder","it is in oncreateview holder type header")
return CategoryViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.categoryheader, parent, false))
}
else
{
Log.d("OncreateViewHolder","it is in oncreateview holder type item")
return ItemViewholder(LayoutInflater.from(parent.context).inflate(R.layout.itemforrecyclerviewinside, parent, false)
)
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int)
{
when (myReceivedData!![position].getviewType())
{
Type_Header ->
{
Log.d("OnBindViewHolder","it is in OnBind holder type header")
(holder as CategoryViewHolder).bind(position)
}
Type_Item ->
{
Log.d("OnTypeViewHolder","it is in OnBind holder type item")
(holder as ItemViewholder).bind(position)
}
}
}
fun returnPositionHedaer(name:String):Int
{
for (hashMap in allHeader)
{
Log.d("itemss",hashMap.key)
if (hashMap.key == name)
{
return hashMap.value
}
}
return 0
}
}
我用类别食物列表动态填充我的 TabLayout 选项卡。我的适配器对 header 项使用相同的类别。
这些部分已经完成。我把它们写在这里是为了更清楚。在这部分我调用 returnPositionHedaer 并将所选选项卡的 tabName 传递给它。这种方法似乎从来没有奏效。
我重复一遍,我在 recyclerview 中有一个动态位置,当在 TabLayout 中单击相关选项卡时,我需要计算要滚动的 header 项的位置。
我在 tabLayout 中的选项卡和 recyclerview 中的项目之间的关系或 link 是名称。
我的方法不行。
您建议采用哪种方法?
菜单片段Class:
//to more clarify,has no problem
private fun setupTabLayout():List<String>
{
if(tabLayout!!.tabCount>0)
CoroutineScope(Dispatchers.Main).launch{tabLayout!!.removeAllTabs()}
for(i in 0 until fullMenu!!.size){
CategoryList.add(i,fullMenu!![i].category)
Log.d("category",CategoryList[i])
}
val tabCategory=CategoryList.distinct()
CoroutineScope(Dispatchers.Main).launch {
if (tabCategory.size > 3)
tabLayout!!.setTabMode(TabLayout.MODE_SCROLLABLE);
else {
tabLayout!!.setTabMode(TabLayout.MODE_FIXED);
tabLayout!!.setTabGravity(TabLayout.GRAVITY_FILL);
}
for (i in 0 until tabCategory.size)
{
tabLayout?.addTab(tabLayout!!.newTab().setText(tabCategory[i]), i)
Log.d("addingtab",tabCategory[i])
}
} } //to more clarify,has no problem
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setupTabLayout()
tabLayout!!.addOnTabSelectedListener(object: TabLayout.OnTabSelectedListener{
override fun onTabReselected(tab: TabLayout.Tab?) {
}
override fun onTabUnselected(tab: TabLayout.Tab?) {
}
override fun onTabSelected(tab: TabLayout.Tab?) {
isUserScrolling = false
val position = tab!!.position
val tabName = tab.text
CoroutineScope(Dispatchers.Main).launch {
recyclerview.smoothScrollToPosition( recyclerAdapter.returnPositionHedaer(tabName.toString()))
//always return 0 position
}
}
})
}
做一个通用的项目class喜欢
data class MyItem(private val item:ItemClass,private headerName:String?=null)
将其传递给您的适配器
RecyclerAdapterInside( PlaceId:String?=null, var myReceivedData: List<MyItem>?=null, val context:Context, private val ButtonFinish:RecyclerAdapterInsideButtonFinishCallback)
然后找位置
fun returnPositionHeader(name:String):Int {
return myReceivedData.indexOfFirst { it.headerName=name }
}
对于有这种挑战的人,我可以轻松应对。您只需要从您的 recyclerview 适配器数据模型创建一个数组。在传递给适配器之前创建一个 属性,例如将其命名为 position。目的是保存数组数据模型中每个项目的位置,并使用计数器为每个数组项目分配位置。最后将它传递给适配器。现在你知道什么项目有什么位置了。
菜单类()
open class ItemClass()
{
private var position = 0
var name: String?=null
var _id: String? =null
var __v: Int? =0
var category: String?=null
var description: String?=null
var image: String? =null
var price: String? =null
var rating: String? =null
open fun ItemHeaderClass(position:Int,viewType: Int, name: String) {
this.position=position
this.viewType = viewType
this.name=name
}
}
菜单片段
for(item in category)
{
val myclass=ItemClass()
myclass.ItemHeaderClass(counter++, 1, item)
calculatedAllItemOfList.add(myclass)
val items = createItemListForRecycler(item, allItem)
calculatedAllItemOfList.addAll(items)
}
我使用 tabLayout 作为 header 用于 recyclerView 适配器。滚动到 recyclerview 项目的静态位置没有问题。例如比萨的位置 2 header.tab 比萨的位置为零。
override fun onTabSelected(tab: TabLayout.Tab?) {
if (tab.position == 0)
recyclerview.smoothScrollToPosition(2)}
问题是我不知道如何滚动到某些 headers 我没有位置的项目的位置。据我所知,我可以获得所有项目位置,直到它们通过 onBindViewHolder 函数在屏幕上可见。正确的。 但是当所有项目都不可见或者我在列表的第一个时,我怎么能得到 headers 的其余位置?例如 drinks header 位置在列表的末尾,当用户单击 drink 选项卡时我需要知道位置。看来不是什么好办法。
我的情况是,我有一个 recyclerview 适配器。它有两种项目类型。
1-Header 项类型(食物类型如:三明治 - 披萨 - ...)
2 项类型(食物如:那不勒斯披萨 - 芝加哥披萨 - ...)
我的方法是:我创建一个哈希图。试图用 Header 项填充它。 <姓名,职位>。 我在onbindviewholder里面填的。正如我之前描述的那样。所有 header 项目的位置不会立即计算,直到我滚动所有列表以结束。所以 returnPositionHedaer 函数总是 return 0.
RecyclerViewAdapter Class:
class RecyclerAdapterInside( PlaceId:String?=null, var myReceivedData: List<ItemClass>?=null, val context:Context, private val ButtonFinish:RecyclerAdapterInsideButtonFinishCallback):RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var allHeader:HashMap<String,Int> = hashMapOf()
companion object {
const val Type_Header = 1
const val Type_Item = 2
}
private inner class CategoryViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var message: TextView = itemView.findViewById(R.id.textViewCategory)
fun bind(position: Int)
{
Log.d("inner Category","it is in CategoryViewHolder Header")
message.text = myReceivedData?.get(position)?.name
allHeader.put(message.text.toString(),position)
Log.d("itemss iewHolder",allHeader.keys.toString())
}
}
private inner class ItemViewholder(itemview: View) : RecyclerView.ViewHolder(itemview) {
val Name = itemview.findViewById(R.id.ItemName) as TextView
val Price = itemview.findViewById(R.id.ItemPrice) as TextView
val Category = itemview.findViewById(R.id.ItemCategory) as TextView
val Image = itemView.findViewById(R.id.ImgInsideMenu) as ImageView
val BtnAdd = itemView.findViewById(R.id.AddBtn) as Button
var count = itemview.findViewById(R.id.showCounter) as TextView
val BtnMin = itemView.findViewById(R.id.MinBtn) as Button
fun bind(position: Int) {
Log.d("value name is","${Name.text}")
Log.d("inner Category","it is in ItemViewHolder Header")
Name.text = myReceivedData!![position].name
Price.text = "Price :" + myReceivedData!![position].price
...
}
override fun getItemViewType(position: Int): Int {
return when (myReceivedData!!.get(position).getviewType()) {
1 -> Type_Header
2 -> Type_Item
else -> -1
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
if (viewType == Type_Header)
{
Log.d("OncreateViewHolder","it is in oncreateview holder type header")
return CategoryViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.categoryheader, parent, false))
}
else
{
Log.d("OncreateViewHolder","it is in oncreateview holder type item")
return ItemViewholder(LayoutInflater.from(parent.context).inflate(R.layout.itemforrecyclerviewinside, parent, false)
)
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int)
{
when (myReceivedData!![position].getviewType())
{
Type_Header ->
{
Log.d("OnBindViewHolder","it is in OnBind holder type header")
(holder as CategoryViewHolder).bind(position)
}
Type_Item ->
{
Log.d("OnTypeViewHolder","it is in OnBind holder type item")
(holder as ItemViewholder).bind(position)
}
}
}
fun returnPositionHedaer(name:String):Int
{
for (hashMap in allHeader)
{
Log.d("itemss",hashMap.key)
if (hashMap.key == name)
{
return hashMap.value
}
}
return 0
}
}
我用类别食物列表动态填充我的 TabLayout 选项卡。我的适配器对 header 项使用相同的类别。
这些部分已经完成。我把它们写在这里是为了更清楚。在这部分我调用 returnPositionHedaer 并将所选选项卡的 tabName 传递给它。这种方法似乎从来没有奏效。 我重复一遍,我在 recyclerview 中有一个动态位置,当在 TabLayout 中单击相关选项卡时,我需要计算要滚动的 header 项的位置。 我在 tabLayout 中的选项卡和 recyclerview 中的项目之间的关系或 link 是名称。 我的方法不行。
您建议采用哪种方法?
菜单片段Class:
//to more clarify,has no problem
private fun setupTabLayout():List<String>
{
if(tabLayout!!.tabCount>0)
CoroutineScope(Dispatchers.Main).launch{tabLayout!!.removeAllTabs()}
for(i in 0 until fullMenu!!.size){
CategoryList.add(i,fullMenu!![i].category)
Log.d("category",CategoryList[i])
}
val tabCategory=CategoryList.distinct()
CoroutineScope(Dispatchers.Main).launch {
if (tabCategory.size > 3)
tabLayout!!.setTabMode(TabLayout.MODE_SCROLLABLE);
else {
tabLayout!!.setTabMode(TabLayout.MODE_FIXED);
tabLayout!!.setTabGravity(TabLayout.GRAVITY_FILL);
}
for (i in 0 until tabCategory.size)
{
tabLayout?.addTab(tabLayout!!.newTab().setText(tabCategory[i]), i)
Log.d("addingtab",tabCategory[i])
}
} } //to more clarify,has no problem
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setupTabLayout()
tabLayout!!.addOnTabSelectedListener(object: TabLayout.OnTabSelectedListener{
override fun onTabReselected(tab: TabLayout.Tab?) {
}
override fun onTabUnselected(tab: TabLayout.Tab?) {
}
override fun onTabSelected(tab: TabLayout.Tab?) {
isUserScrolling = false
val position = tab!!.position
val tabName = tab.text
CoroutineScope(Dispatchers.Main).launch {
recyclerview.smoothScrollToPosition( recyclerAdapter.returnPositionHedaer(tabName.toString()))
//always return 0 position
}
}
})
}
做一个通用的项目class喜欢
data class MyItem(private val item:ItemClass,private headerName:String?=null)
将其传递给您的适配器
RecyclerAdapterInside( PlaceId:String?=null, var myReceivedData: List<MyItem>?=null, val context:Context, private val ButtonFinish:RecyclerAdapterInsideButtonFinishCallback)
然后找位置
fun returnPositionHeader(name:String):Int {
return myReceivedData.indexOfFirst { it.headerName=name }
}
对于有这种挑战的人,我可以轻松应对。您只需要从您的 recyclerview 适配器数据模型创建一个数组。在传递给适配器之前创建一个 属性,例如将其命名为 position。目的是保存数组数据模型中每个项目的位置,并使用计数器为每个数组项目分配位置。最后将它传递给适配器。现在你知道什么项目有什么位置了。
菜单类()
open class ItemClass()
{
private var position = 0
var name: String?=null
var _id: String? =null
var __v: Int? =0
var category: String?=null
var description: String?=null
var image: String? =null
var price: String? =null
var rating: String? =null
open fun ItemHeaderClass(position:Int,viewType: Int, name: String) {
this.position=position
this.viewType = viewType
this.name=name
}
}
菜单片段
for(item in category)
{
val myclass=ItemClass()
myclass.ItemHeaderClass(counter++, 1, item)
calculatedAllItemOfList.add(myclass)
val items = createItemListForRecycler(item, allItem)
calculatedAllItemOfList.addAll(items)
}