3

Я создаю список с RecyclerView. Каждый элемент списка - это сообщение от пользователя (прямо сейчас жестко закодировано). Фон для каждого сообщения загружается из XML-файла layer-list в выпадающей папке.Android RecyclerView не меняет цвет фона на первый элемент программно

Все работает по назначению с текстами и т. Д., Но я пытаюсь изменить цвет фона программно. Он изменяет цвет фона для каждого элемента, за исключением для первого элемента, и я не могу понять, почему.

Первый элемент всегда получает цвет фона, заданный solid цвета shape внутри item называется shape_background в файле XML, так что не меняется, но следующие пункты получить цвет #ff22ff.

Это реализация адаптера:

class PostListAdapter extends RecyclerView.Adapter<PostListAdapter.PostViewHolder>{ 

    private LayoutInflater inflater; 
    private List<PostRow> data = Collections.emptyList(); 

    PostListAdapter(Context context, List<PostRow> data) { 
     inflater = LayoutInflater.from(context); 
     this.data = data; 
    } 

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

     PostRow current = data.get(position); 
     holder.text.setText(current.text.toUpperCase()); 
     holder.time.setText(current.time.toUpperCase()); 
     holder.answers.setText(current.answers.toUpperCase()); 

     try { 
      // "#ff22ff" will be changed to current.color, unique color for every post 
      // That string is parsed from a JSON request, hence the try-catch. 
      int color = Color.parseColor("#ff22ff"); 
      holder.shape.setColor(color); 
     } catch (Exception e){ 
      e.printStackTrace(); 
     } 

    } 

    @Override 
    public PostViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
     View view = inflater.inflate(R.layout.post_row, parent, false); 
     return new PostViewHolder(view); 
    } 

    @Override 
    public int getItemCount() { 
     return data.size(); 
    } 

    class PostViewHolder extends RecyclerView.ViewHolder { 

     TextView text; 
     TextView time; 
     TextView answers; 
     GradientDrawable shape; 

     PostViewHolder(View itemView) { 
      super(itemView); 
      text = (TextView) itemView.findViewById(R.id.text); 
      time = (TextView) itemView.findViewById(R.id.time); 
      answers = (TextView) itemView.findViewById(R.id.answers); 
      LayerDrawable layers = (LayerDrawable) ContextCompat.getDrawable(itemView.getContext(), R.drawable.bubble); 

      shape = (GradientDrawable) (layers.findDrawableByLayerId(R.id.shape_background)); 
     } 

    } 

} 

Почему фон первого элемента не изменяется, но тексты?

Спасибо заранее!

+3

Есть ли у вас какие-либо исключения? Зачем пытаться поймать? – natario

+0

Я понимаю, что комментарий был недостаточно ясным. Строка с жесткой кодировкой «# ff22ff» будет позже изменена на строку current.color. Эта строка анализируется из ответа JSON. Так что на случай, если что-то запутается в этом процессе, объедините это с помощью try-catch. Я буду обновлять комментарий, спасибо. – Misklahr

ответ

3

На вашем onBindViewHolder, получить вид (от владельца) для этого вам нужно изменить цвет фона & получить свой текущий фон (рисует пузырь, что вы уже установили в атрибуте XML)

LayerDrawable layerDrawable = (LayerDrawable) yourView.getBackground().getCurrent(); 
GradientDrawable gradientDrawable = (GradientDrawable) layerDrawable.findDrawableByLayerId(R.id. shape_background).getCurrent(); 
// set you color based on position 
gradientDrawable.setColor(Color.parseColor("#ff22ff")); 
+0

Спасибо, это решило мою проблему так, как я хотел. Используя API 15 и выше, поэтому setBackground в ответе liubaoyua не может быть использован в моем случае, но он также правильный. – Misklahr

3

вы назвали holder.shape.setColor(color);

но держательView не обновлен.

может быть, вы должны позвонить

holder.itemView.setBackgroundDrawable( ContextCompat.getDrawable(itemView.getContext(), R.drawable.bubble))

обновить holderView

+0

Это правильно, обратите внимание, что setBackgroundDrawable устарел. Нужно использовать setBackground для уровня API 16 и выше, хотя setBackground вызывает метод setBackgroundDrawable. – Misklahr

0

У вас есть две различные проблемы здесь.

Во-первых - вы сами меняете свой собственный, но не видите фон. Он решается на ответах liubaoyua и Vignesh Sundar.

Второй - вы меняете R.drawable.bubble статически. Android может кэшировать и повторно использовать его даже после мутации. Это может привести к другим проблемам, когда вы начинаете использовать разные цвета для разных предметов.

Чтобы решить вторую проблему, вы должны позвонить android.graphics.drawable.Drawable#mutate каждый раз, прежде чем сначала ее мутировать.

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

Так это должно выглядеть примерно так:

class PostViewHolder extends RecyclerView.ViewHolder { 

    TextView text; 
    TextView time; 
    TextView answers; 
    LayerDrawable layers; 
    GradientDrawable shape; 

    PostViewHolder(View itemView) { 
     super(itemView); 

     text = (TextView) itemView.findViewById(R.id.text); 
     time = (TextView) itemView.findViewById(R.id.time); 
     answers = (TextView) itemView.findViewById(R.id.answers); 

     layers = (LayerDrawable) ContextCompat 
       .getDrawable(itemView.getContext(), R.drawable.bubble) 
       .mutate(); 

     shape = (GradientDrawable) layers.findDrawableByLayerId(R.id.shape_background); 
     itemView.setBackground(layers); 
    } 

    void setColor(Color color) { 
     shape.setColor(color); 
     itemView.setBackgroundDrawable(layers); 
    } 
} 

Может быть, может быть немного упрощенным путем перемещения .mutate() от слоя к форме.