簡體   English   中英

顯示后如何檢測每個 RecyclerView 項目

[英]How to detect each RecyclerView item after it is displayed

我想在RecylerView顯示給用戶后檢測每個項目。

基本上,我試圖在每個項目加載到屏幕后播放聲音。

但是我無法檢測到每個項目何時加載到屏幕上! 有什么方法我必須調用來檢測呈現的每個項目

E.g 1st RecyclerView item displayed -> play sound
    2st RecyclerView item displayed -> play sound...

我的適配器類看起來像這樣 -

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;
    .........
    .........

我從onCreated()方法調用這個initComponent() ) 方法。 您能否就我應該怎么做才能實現上述目標提供建議?

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

您需要覆蓋onViewAttachedToWindowonViewDetachedFromWindow 但是為了檢測空洞類型,您需要getItemViewType()就像這樣:

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

    }
}

您可以在適配器中簡單地使用 onViewAttachedToWindow(VH) 。 請參閱https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter.html#onViewAttachedToWindow(VH)

更新:

如您所知,對於每個項目, RecyclerView只會調用一次OnBindViewHolder

如果item在數據集中的位置發生變化,RecyclerView不會再次調用該方法,除非item本身失效或者無法確定新的位置。

所以你可以使用onViewAttachedToWindow

(onViewAttachedToWindow) 當此適配器創建的視圖已附加到窗口時調用。

這可以用作用戶即將看到視圖的合理信號。 如果適配器之前釋放了 onViewDetachedFromWindow 中的任何資源,則應在此處恢復這些資源。

你可以像這樣使用它:

public class Adapter extends RecyclerView.Adapter<MyViewHolder> {
   
    // rest of your code

   
    @Override
    public void onViewAttachedToWindow(MyViewHolder holder) {
         super.onViewAttachedToWindow(holder);
        // play your sound
    }
}

希望能幫助到你!

您需要為 TTS 添加監聽器。 然后更新您的RecyclerView以在語音開始和結束時顯示正確的圖像。

我創建了一個測試項目來展示它是如何實現的。 在這里你可以看到它是如何工作的。 是我的 github 存儲庫。

這是我的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) {
    }
}

如果我正確理解了您的問題,您希望在加載RecyclerView中的項目時播放聲音。

因此,我想在這里想一個解決方法。 您可以考慮在播放前一個項目的聲音后添加一個項目。

我想為我試圖解釋的內容提供一個偽代碼。 如果您的聲音停止播放,您可以考慮使用MediaPlayer.OnCompletionListener來監聽,然后將下一個項目添加到RecyclerView ,然后在適配器上調用notifyDataSetChanged以加載RecyclerView中的下一個項目。

因此,您可能希望首先在適配器中進行以下修改。

// Declare a function in your adapter which adds new item in the RecyclerView
public void addItem(Multiples item) {
    items.add(item);
    notifyItemInserted(items.size());
}

現在在您設置RecyclerViewActivity中,您需要具有以下數組。

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(); 

如下修改您的函數。

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
}

由於items已從構造函數中刪除,因此您還需要修改適配器的構造函數。 只需刪除接受items的變量。 因為我們稍后將向items添加元素。

然后,您需要在調用initComponent函數后編寫另一個需要在活動的onCreate函數中調用的函數。 該函數應如下所示。

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

我沒有測試過代碼,但是,我想你已經明白了。 這也可以使用適配器內部的interface優雅地實現。 實施技術是您的選擇。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM