更改一个ViewHolder项也会影响其他项

时间:2019-03-21 16:58:39

标签: java android android-recyclerview android-arrayadapter recycler-adapter

我有一个基于 RecyclerView 的简单mp3播放器。 有一个适配器 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 个答案:

答案 0 :(得分:1)

您不能直接更改视图的颜色。在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);
}