Как прокручивать с помощью smoothScrollToPosition RecyclerView с динамической позицией в recyclerview?

#android #android-recyclerview #android-tablayout

#Android #android-recyclerview #android-tablayout

Вопрос:

Я использую TabLayout в качестве заголовка для адаптера RecyclerView. У меня нет проблем с прокруткой до статической позиции элементов recyclerview. например, позиция 2 для заголовка пиццы.нулевая вкладка для пиццы.

 override fun onTabSelected(tab: TabLayout.Tab?) {
if (tab.position == 0)
recyclerview.smoothScrollToPosition(2)}
 

Проблема в том, что я не знаю, как прокручивать до позиции некоторых элементов заголовков, у которых у меня нет их позиций. насколько я знаю, я могу получить все позиции элементов, пока они не будут видны на экране с помощью функции onBindViewHolder. правильно.
Но когда все элементы не видны или я нахожусь в первом списке, как я могу получить остальные позиции заголовков? например, позиция заголовка «Напитки» находится в конце списка, и мне нужно знать позицию, когда пользователь нажимает на вкладку «Напитки», чтобы перейти. Кажется, это не очень хороший подход.

мой сценарий таков, что у меня есть адаптер recyclerview. Он имеет два типа элементов.

1-Тип элементов заголовка (тип еды, например: сэндвич — Пицца — …)

2-тип элемента (например, неаполитанская пицца — Чикагская пицца — …)

мой подход был таков: я создаю hashmap. попытался заполнить его только элементами заголовка. <Имя, позиция>. Я заполнил его в onbindviewholder. как я описал это ранее. Позиции всех элементов заголовка не вычисляются сразу, пока я не прокручиваю весь список до конца.поэтому функция returnPositionHedaer всегда возвращает 0.

Класс RecyclerViewAdapter:

 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 списком продуктов категории. мой адаптер использует ту же категорию для элементов заголовка.

эти части проработаны. Я пишу их здесь, чтобы уточнить.В этой части я вызываю returnPositionHedaer и передаю ему имя вкладки выбранной вкладки. этот метод, похоже, никогда не работал. Я повторяю, что у меня есть динамическая позиция в recyclerview, и мне нужно рассчитать позиции элементов заголовка для прокрутки при нажатии соответствующей вкладки в TabLayout. мое отношение или связь между вкладкой в TabLayout и элементом в recyclerview — Name. мой метод не работает.

какой подход вы предлагаете?

Класс MenuFragment:

 //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
}
            }
        })
}
 

Ответ №1:

создайте общий класс элементов, например

 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 }
}
 

Ответ №2:

Для тех, у кого есть эта проблема, я мог бы легко с ней справиться. Вам просто нужно создать массив из вашей модели данных адаптера recyclerview. перед передачей адаптеру создайте свойство, например, назовите его poistion. цель состоит в том, чтобы сохранить положение каждого элемента в вашей модели данных массива и использовать счетчик для назначения позиции каждому элементу массива. наконец, передайте его адаптеру. Теперь вы знаете, какой элемент имеет какую позицию.

MenuClass()

 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
        }

}
 

MenuFragment

 for(item in category)
        {
            val myclass=ItemClass()
            myclass.ItemHeaderClass(counter  , 1, item)
            calculatedAllItemOfList.add(myclass)

            val items = createItemListForRecycler(item, allItem)
            calculatedAllItemOfList.addAll(items)
        }