2

I want to Highlight a single row of recyclerview with sound one after another and scroll the highlight row to top of screen This is what i have done:

screenshot

Here its code:

 fun AnimateToSurahAlFeel(recyclerView: RecyclerView, layoutManager: LinearLayoutManager, currentPosition: Int) {

        var position: Int = currentPosition / 1000


        when (position) {


            0 -> {
                recyclerView.smoothScrollToPosition(0)
                recyclerView.getChildAt(0).isSelected = true

            }
            4 -> {
                recyclerView.smoothScrollToPosition(1)
                recyclerView.getChildAt(0).isSelected = false
                recyclerView.getChildAt(1).isSelected = true
            }
            11 -> {
                recyclerView.smoothScrollToPosition(2)
                recyclerView.getChildAt(1).isSelected = false
                recyclerView.getChildAt(2).isSelected = true
            }
            17 -> {
                recyclerView.smoothScrollToPosition(3)
                recyclerView.getChildAt(2).isSelected = false
                recyclerView.getChildAt(3).isSelected = true
            }
            21 -> {
                recyclerView.smoothScrollToPosition(4)
                recyclerView.getChildAt(3).isSelected = false
                recyclerView.getChildAt(4).isSelected = true
            }
            28 -> {
                recyclerView.smoothScrollToPosition(5)
                recyclerView.getChildAt(4).isSelected = false

                if (recyclerView.getChildAt(5) != null)
                    recyclerView.getChildAt(5).isSelected = true
            }

        }
    }

In the Function currentPosition is Media player current position

Problem in this code is:

In the Screen shot Row 4 and 5 are currently not visible,when highlighting Row 4 and 5 the App crash and giving Null Pointer Exception, according to my knowledge these two row are not yet created that's why

recyclerview.getChildAt(4) or recyclerview.getChildAt(5) return null and that cause the App crash.

Now

  1. How to fix the App crash that recyclerview.getchildAt(4) or recyclerview.getchildAt(5) return null and also getChildAt(position) return n-1 row, so the App crash at recyclerview.getchildAt(5) will occur anyhow but i want n Row because i want to highlight all rows

  2. How to scroll the highlighted row to position 0 (at top) i.e. Row 0 go up from screen and Row 1 take it position and so on...

I want to achieve like this the highlighted one is at top and that will go off from screen when another row is highlighted

picture

James Z
  • 12,209
  • 10
  • 24
  • 44

2 Answers2

0

You need time for View to Bind. Just for ex. you can post action.

....
 17 -> {
                recyclerView.smoothScrollToPosition(3)
                new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {

                      recyclerView.getChildAt(2).isSelected = false
                      recyclerView.getChildAt(3).isSelected = true
                }, 500);
            }
....

But I strongly recommend you use some state Collection, which will save and handle states of your running and showing Views.

GensaGames
  • 5,538
  • 4
  • 24
  • 53
  • From MainActivity already calling this method after 400ms mUIRunnable = object : Runnable{ override fun run() { if(mHandler!=null){ mHandler!!.postDelayed(this,400) SurahAnimator.AnimateToSurahAlFeel(recyclerViewSurahContent,linearLayoutManager!!,mediaPlayer!!.currentPosition) } } } mHandler!!.post(mUIRunnable) –  Jun 12 '18 at 04:18
0

This is because recycler views don't have all the views inflated, but only the visible ones. This is by design and should not be tinkered with. Personally, I think you should use the recycling functionality.

You need to make the selected state part of your model in the adapter - the items in the adapter. Let's say this is called RowItem, so in your adapter you'd have a list of RowItems for example. Aside from the text in both languages, you need to add the selected state too. Then it's just a matter of getting the list's adapter, setting the correct position to selected and deselecting the ones you want.

For example, in your adapter:

fun select(position: Int) {
  data[position].selected = true
  notifyItemChanged(position)
  // deselect all other positions that you don't want selected
}

When you bind the view holder you could do then:

public void onBindViewHolder(ViewHolder viewHolder, int position) {
   val item = data[position]
   viewHolder.itemView.selected = item.selected
   // take care of the rest of the views
}

data would be a list where you store your RowItems

Now you can scroll with no problem and set the item to selected. Once the view is visible in the recycler view, the adapter will set the correct state.

It's fair to say I'm guessing a bit since there's no adapter code in your question, but the idea I think it's easy to understand. You need to change the state in the adapter and let the implementation of the recycler view handle it for you. After all the purpose is to get the recycler view to recycle your views based on the models adapted by the adapter.

Remember you can always get your adapter from the recycler view itself. In the end you can do something like this:

...
0 -> {
     recyclerView.smoothScrollToPosition(0)
     (recyclerView.adapter as MyAdapter).select(0)
}

Here MyAdapter would be the class name of your adapter

For the scrolling part you can take a look at this

Fred
  • 16,367
  • 6
  • 50
  • 65
  • At the time of item inflation in adapter i don't want to select any item,in the screenshot i have two button play and stop, when i click play button then i want to select item according to recitation of Quran –  Jun 12 '18 at 04:10
  • When i click on play button below code is called mUIRunnable = object : Runnable{ override fun run() { if(mHandler!=null){ mHandler!!.postDelayed(this,400) SurahAnimator.AnimateToSurahAlFeel(recyclerViewSurahContent,linearLayoutManager!!,mediaPlayer!!.currentPosition) } } } mHandler!!.post(mUIRunnable) ..... and that will call the Above method AnimateToSurahAlFeel() –  Jun 12 '18 at 04:15
  • I don't understand why any of what you said prevents you from doing what I said. At time of inflation just don't select anything. When the `onBindViewHolder` gets called, then select them as needed. This method gets called as the views are shown, that's why selecting them from your animation (like you already have) and scrolling to them would trigger calls to the `onBindViewHolder`. The difference is that now the adapter knows they have to be selected or not. This is how you're suppose to use recycler views. – Fred Jun 12 '18 at 06:06