Изменение одного элемента ViewHolder также влияет на другие элементы - PullRequest
0 голосов
/ 21 марта 2019

У меня есть простой mp3-плеер на основе RecyclerView . Существует Адаптер и ViewHolder для обработки треков в списке воспроизведения.

public class TracksAdapter extends RecyclerView.Adapter<TracksAdapter.ViewHolder> {

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

        View v = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.cell_playlist, parent, false);

        return new ViewHolder(v);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {

        holder.trackName.setText("Track " + position);
    }

    @Override
    public int getItemCount() {

        return tracks.size();
    }

    class ViewHolder extends RecyclerView.ViewHolder {

        final TextView trackName;

        ViewHolder(View itemView) {

            super(itemView);

            trackName = itemView.findViewById(R.id.trackName);
        }
    }
}

Когда я нажимаю на дорожку, я хочу изменить цвет фона выбранной дорожки в списке воспроизведения. Проблема в том, что когда я устанавливаю цвет фона для одного элемента, он будет влиять на каждую десятую ячейку в списке воспроизведения.

Например, если в списке воспроизведения 100 треков, будет выделено 10 треков, включая выбранные.

Метод findViewHolderForAdapterPosition (position) возвращает ViewHolder с выбранной дорожкой.

private void setTrackColor(int position) {

    RecyclerView.ViewHolder holder =
        recyclerView.findViewHolderForAdapterPosition(position);

    if (holder == null) return;

    View item = holder.itemView;
    item.setBackgroundColor(ContextCompat.getColor(main, R.color.playing)); 
}

1 Ответ

1 голос
/ 21 марта 2019

Вы не можете изменить цвет вида напрямую.В RecyclerView все Views используются повторно.Таким образом, если вы измените цвет в позиции, вы можете произвольно изменить цвет в других позициях, потому что тот же самый вид будет использоваться повторно.

Вы должны сохранить положение текущей воспроизводимой дорожки отдельно.Таким образом, во время onBindViewHolder вы проверяете, является ли текущий привязываемый вид дорожкой, воспроизводимой в данный момент.Если это тот же трек, примените цвет.Если это не тот же цвет, восстановите цвет по умолчанию

public class TracksAdapter extends RecyclerView.Adapter<TracksAdapter.ViewHolder> {

    private int mTrackPlaying = -1;

    public void setTrackPlaying(int position) {
        mTrackPlaying = position;
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        holder.trackName.setText("Track " + position);
        if(position == mTrackPlaying) {
            holder.itemView.setBackgroundColor(ContextCompat.getColor(main, R.color.playing)); 
        } else {
            // Here, you must restore the color because the view is reused.. so, you may receive a reused view with wrong colors
            holder.itemView.setBackgroundColor(ContextCompat.getColor(main, R.color.NOT_playing)); 
        }
    }
}

А затем

private void setTrackColor(int position) {
    TracksAdapter adapter = (TracksAdapter) recyclerView.getAdapter();
    adapter.setTrackPlaying(position);
    // Line below will `RecyclerView` to re-draw that position.. in other words, it will triggers a call to `onBindViewHolder`
    adapter.notifyItemChanged(position);

    // Reset the color of song previously playing.. 
    adapter.notifyItemChanged(oldPosition);
}
...