Je veux détecter chaque élément dans mon RecylerView après l'avoir affiché à l'utilisateur.
Fondamentalement, j'essaye de jouer un son sur chaque élément après qu'il soit chargé sur l'écran.
Mais je ne suis pas en mesure de détecter chaque fois que chaque élément est chargé sur l'écran! Existe-t-il une méthode que je dois appeler pour détecter chaque élément rendu
E.g 1st RecyclerView item displayed -> play sound
2st RecyclerView item displayed -> play sound...
Ma classe d'adaptateur ressemble à ceci -
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;
.........
.........
J'appelle cette méthode initComponent()
à partir de la méthode onCreated()
. Pouvez-vous donner des conseils sur ce que je dois faire pour atteindre mon objectif tel que décrit ci-dessus?
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();
}
});
}
Vous devez ajouter un écouteur pour TTS. Mettez ensuite à jour votre RecyclerView
pour afficher la bonne image lorsque la parole commence et se termine.
J'ai créé un projet de test pour montrer comment il peut être mis en œuvre. Ici vous pouvez voir comment cela fonctionne. Ici est mon dépôt github.
Voici la partie principale de ma classe MainActivity
.
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) {
}
}
Vous pouvez simplement utiliser onViewAttachedToWindow (VH) dans votre adaptateur. Voir https://developer.Android.com/reference/Android/support/v7/widget/RecyclerView.Adapter.html#onViewAttachedToWindow (VH)
Mise à jour:
Comme vous le savez, RecyclerView
sera appelé OnBindViewHolder
une seule fois pour chaque élément.
RecyclerView n'appellera plus cette méthode si la position de l'élément change dans l'ensemble de données, sauf si l'élément lui-même est invalidé ou si la nouvelle position ne peut pas être déterminée.
Vous pouvez donc utiliser onViewAttachedToWindow
(onViewAttachedToWindow) Appelé lorsqu'une vue créée par cet adaptateur a été attachée à une fenêtre.
Cela peut être utilisé comme un signal raisonnable que la vue est sur le point d'être vue par l'utilisateur. Si l'adaptateur précédemment libéré toutes les ressources dans onViewDetachedFromWindow, ces ressources doivent être restaurées ici.
Vous pouvez l'utiliser comme ceci:
public class Adapter extends RecyclerView.Adapter<MyViewHolder> {
// rest of your code
@Override
public void onViewAttachedToWindow(MyViewHolder holder) {
super.onViewAttachedToWindow(holder);
// play your sound
}
}
J'espère que ça aide!
Si j'ai bien compris votre problème, vous voulez jouer un son lorsqu'un élément du RecyclerView
est chargé.
Par conséquent, je voudrais penser à une solution de contournement ici. Vous pourriez envisager d'ajouter un élément après la lecture du son de l'élément précédent.
Je voudrais fournir un pseudo-code pour ce que j'essaie d'expliquer. Vous pourriez envisager d'utiliser le MediaPlayer.OnCompletionListener
pour écouter si votre son a cessé de jouer, puis ajoutez l'élément suivant au RecyclerView
puis appelez notifyDataSetChanged
sur votre adaptateur pour charger l'élément suivant dans votre RecyclerView
.
Par conséquent, vous souhaiterez peut-être d'abord la modification suivante dans votre adaptateur.
// Declare a function in your adapter which adds new item in the RecyclerView
public void addItem(Multiples item) {
items.add(item);
notifyItemInserted(items.size());
}
Maintenant, dans votre Activity
où vous configurez le RecyclerView
, vous devez avoir les tableaux suivants.
ArrayList<Multiples> allItems = new ArrayList<Multiples>(); // This list will contain all the data
int soundToBePlayed = -1; // Initialize the value with -1
ArrayList<Integer> soundList = getAllSoundsInAList();
Modifiez vos fonctions comme suit.
private void initComponent() {
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setHasFixedSize(true);
allItems = DataGenerator.getPeopleData(this,of,value);
setAdapter();
}
private void setAdapter() {
mAdapter = new AdapterListAnimation(this, animation_type); // Do not pass the items list
recyclerView.setAdapter(mAdapter);
// .. Your item click listener goes here
}
Comme items
a été supprimé du constructeur, vous devez également modifier le constructeur de votre adaptateur. Supprimez simplement la variable qui prend le items
. Parce que nous ajouterons des éléments au items
plus tard.
Ensuite, vous devez écrire une autre fonction qui doit être appelée dans votre fonction onCreate
de votre activité après avoir appelé votre fonction initComponent
. La fonction doit ressembler à ce qui suit.
private void addItemInRecyclerViewAndPlaySound() {
soundToBePlayed++;
adapter.addItem(allItems.get(soundToBePlayed));
recyclerView.scrollToPosition(adapter.getItemCount() - 1);
Integer soundId = soundList.get(soundToBePlayed);
MediaPlayer mp = MediaPlayer.create(this, soundId);
if (mp.isPlaying()) {
mp.stop();
mp.release();
mp = MediaPlayer.create(this, soundId);
mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
// Call this function again to add next item
// and play the next sound at the same time
if(soundToBePlayed < allItems.size() - 1)
addItemInRecyclerViewAndPlaySound();
}
});
}
mp.start();
}
Je n'ai pas testé le code, cependant, je pense que vous avez déjà l'idée. Cela peut être implémenté gracieusement à l'aide d'un interface
à l'intérieur de l'adaptateur. La technique d'implémentation est votre choix.