How to detect each RecyclerView item after it is displayed
Solution 1
You need to add listener for TTS. Then update your RecyclerView
to show right image when speech starts and ends.
I've created a test project to show how it can be implemented. Here you can see how it works. Here is my github repository.
Here is main part of my MainActivity
class.
private void initTts() {
tts = new TextToSpeech(this, this);
tts.setLanguage(Locale.US);
tts.setOnUtteranceProgressListener(new MyListener());
}
@Override
public void onInit(int status) {
playSound(0);
}
private void playSound(int index) {
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, String.valueOf(index));
tts.speak(data.get(index), TextToSpeech.QUEUE_ADD, hashMap);
}
class MyListener extends UtteranceProgressListener {
@Override
public void onStart(String utteranceId) {
int currentIndex = Integer.parseInt(utteranceId);
mMainAdapter.setCurrentPosition(currentIndex);
handler.post(new Runnable() {
@Override
public void run() {
mMainAdapter.notifyDataSetChanged();
}
});
}
@Override
public void onDone(String utteranceId) {
int currentIndex = Integer.parseInt(utteranceId);
mMainAdapter.setCurrentPosition(-1);
handler.post(new Runnable() {
@Override
public void run() {
mMainAdapter.notifyDataSetChanged();
}
});
if (currentIndex < data.size() - 1) {
playSound(currentIndex + 1);
}
}
@Override
public void onError(String utteranceId) {
}
}
Solution 2
you need to override onViewAttachedToWindow
and onViewDetachedFromWindow
. but for detecting holer type you need getItemViewType()
just like that:
public class PostAdapter extends RecyclerView.Adapter {
@Override
public int getItemViewType(int position) {
switch (types.get(position)){
case 1:
return 1;
case 2:
return 2;
default:
return position;
}
}
@Override
public void onViewAttachedToWindow(@NonNull RecyclerView.ViewHolder holder) {
super.onViewAttachedToWindow(holder);
if (holder.getItemViewType() == 1){
//play song
}
}
@Override
public void onViewDetachedFromWindow(@NonNull RecyclerView.ViewHolder holder) {
super.onViewDetachedFromWindow(holder);
if (holder.getItemViewType() == 1){
//pause song
}
}
Solution 3
You can simply use onViewAttachedToWindow(VH) in your adapter. See https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter.html#onViewAttachedToWindow(VH)
Update:
As you know RecyclerView
will be call OnBindViewHolder
only once for each item.
RecyclerView will not call this method again if the position of the item changes in the data set unless the item itself is invalidated or the new position cannot be determined.
So you can use onViewAttachedToWindow
(onViewAttachedToWindow) Called when a view created by this adapter has been attached to a window.
This can be used as a reasonable signal that the view is about to be seen by the user. If the adapter previously freed any resources in onViewDetachedFromWindow those resources should be restored here.
You can use it like this:
public class Adapter extends RecyclerView.Adapter<MyViewHolder> {
// rest of your code
@Override
public void onViewAttachedToWindow(MyViewHolder holder) {
super.onViewAttachedToWindow(holder);
// play your sound
}
}
Hope it helps!
Dan
Updated on July 26, 2022Comments
-
Dan almost 2 years
I want to detect each item in my RecylerView after it is displayed to the user.
Basically, I am trying to play a sound on each item after it is loaded on the screen.
But I am not able to detect whenever each item is loaded on the screen! Is there any method I have to call to detect each item rendered
E.g 1st RecyclerView item displayed -> play sound 2st RecyclerView item displayed -> play sound...
My Adapter class looks like this -
public class AdapterListAnimation extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private List<Multiples> items = new ArrayList<>(); private Context ctx; private OnItemClickListener mOnItemClickListener; private int animation_type = 0; ......... .........
I am calling this
initComponent()
method fromonCreated()
method. Can you give advice on what should I do to achieve my goal as described above?private void initComponent() { recyclerView = (RecyclerView) findViewById(R.id.recyclerView); recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setHasFixedSize(true); items = DataGenerator.getPeopleData(this,of,value); setAdapter(); /* MediaPlayer mp=MediaPlayer.create(this, R.raw.sword); if (mp.isPlaying()) { mp.stop(); mp.release(); mp = MediaPlayer.create(this, R.raw.sword); } mp.start();*/ } private void setAdapter() { // Set data and list adapter mAdapter = new AdapterListAnimation(this, items, animation_type); recyclerView.setAdapter(mAdapter); // on item list clicked mAdapter.setOnItemClickListener(new AdapterListAnimation.OnItemClickListener() { @Override public void onItemClick(View view, com.math.multiplication.model.Multiples obj, int position) { Snackbar.make(parent_view, "Item " + obj.first + " clicked", Snackbar.LENGTH_SHORT).show(); } }); }
-
Dan about 5 yearsI could not understand your answer. Plz elaborate it . I have updated my question.
-
Dan about 5 years@Override is showing error as there is no method to overide
-
Amin Mastani about 5 yearsReplace
MyViewHolder
withRecyclerView.ViewHolder
-
Dan about 5 yearsHi ! Please help me on same question: stackoverflow.com/q/55516858/1684778 I have explained here very clearly & better way. I think you can only in SO can help me
-
FindOutIslamNow about 4 years
As you know RecyclerView will be call OnBindViewHolder only once for each item.
Not necessary. RecyclerView can "re"use a view holder again and again