web-dev-qa-db-fra.com

Comment détecter chaque élément RecyclerView après son affichage

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();
        }
    });
}
6
Dan

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) {
    }
}
1
Andrew Churilo

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!

0
Amin Mastani

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.

0
Reaz Murshed