Изменение цвета фона выбранного элемента в recyclerview

Как изменить цвет фона только выбранного вида в моем примере просмотра корзины? нужно изменить только цвет фона щелкнутого элемента itemview. Только один выбранный элемент должен отображаться с изменением цвета фона за раз, а остальное должно быть как и перед выбором. вот мой код:

MainActivity

public class MainActivity extends AppCompatActivity {
RecyclerView rv1;
    private  final String android_versions[]={
                "Donut",
                "Eclair",
                "Froyo",
                "Gingerbread",
                "Honeycomb",
                "Ice Cream Sandwich",
                "Jelly Bean",
                "KitKat",
                "Lollipop",
                "Marshmallow"
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initViews();
    }

    private  void initViews(){
        rv1=(RecyclerView)findViewById(R.id.recyclerView1);
        rv1.setHasFixedSize(true);
        RecyclerView.LayoutManager layoutManager=new LinearLayoutManager(getApplicationContext());
        rv1.setLayoutManager(layoutManager);

        RecyclerDataAdapter rda=new RecyclerDataAdapter(rv1,getApplicationContext(),android_versions);
        rv1.setAdapter(rda);
    }
}

RecyclerDataadapter

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

private String android_versionnames[];
    private Context context1;

    private RecyclerView mRecyclerView;


    public RecyclerDataAdapter(RecyclerView recylcerView,Context context,String android_versionnames[]){
        this.android_versionnames=android_versionnames;
        this.context1=context;
mRecyclerView=recylcerView;
        setHasStableIds(true);
        System.out.println("Inside dataadapter,Android names : \n ");
        for(int i=0;i<android_versionnames.length;i++){
            System.out.println("\n"+android_versionnames[i]);
        }
    }


    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.row_layout,parent,false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(final ViewHolder holder, int position) {
        holder.tv1.setText(android_versionnames[position]);
    }


    @Override
    public int getItemCount() {
        return android_versionnames.length;
    }


    public class ViewHolder extends RecyclerView.ViewHolder {
        private TextView tv1;
        LinearLayout row_linearlayout;
        RecyclerView rv2;

        public ViewHolder(final View itemView) {
            super(itemView);
            tv1=(TextView)itemView.findViewById(R.id.txtView1);
            row_linearlayout=(LinearLayout)itemView.findViewById(R.id.row_linrLayout);
            rv2=(RecyclerView)itemView.findViewById(R.id.recyclerView1);
            /*itemView.setBackgroundColor(0x00000000);//to transparent*/

        }
    }
}

Ответ 1

Наконец-то я получил ответ.

public void onBindViewHolder(final ViewHolder holder, final int position) {
        holder.tv1.setText(android_versionnames[position]);

        holder.row_linearlayout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                row_index=position;
                notifyDataSetChanged();
            }
        });
        if(row_index==position){
            holder.row_linearlayout.setBackgroundColor(Color.parseColor("#567845"));
            holder.tv1.setTextColor(Color.parseColor("#ffffff"));
        }
        else
        {
            holder.row_linearlayout.setBackgroundColor(Color.parseColor("#ffffff"));
            holder.tv1.setTextColor(Color.parseColor("#000000"));
        }

    }

здесь 'row_index' изначально устанавливается как '-1'

public class ViewHolder extends RecyclerView.ViewHolder {
        private TextView tv1;
        LinearLayout row_linearlayout;
        RecyclerView rv2;

        public ViewHolder(final View itemView) {
            super(itemView);
            tv1=(TextView)itemView.findViewById(R.id.txtView1);
            row_linearlayout=(LinearLayout)itemView.findViewById(R.id.row_linrLayout);
            rv2=(RecyclerView)itemView.findViewById(R.id.recyclerView1);
        }
    }

Ответ 2

Очень простой способ добиться этого:

//instance variable
List<View>itemViewList = new ArrayList<>();

//OnCreateViewHolderMethod
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {    
    final View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_row, parent, false);
    final MyViewHolder myViewHolder = new MyViewHolder(itemView);

    itemViewList.add(itemView); //to add all the 'list row item' views

    //Set on click listener for each item view
    itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            for(View tempItemView : itemViewList) {
                /** navigate through all the itemViews and change color
                of selected view to colorSelected and rest of the views to colorDefault **/
                if(itemViewList.get(myViewHolder.getAdapterPosition()) == tempItemView) {
                    tempItemView.setBackgroundResource(R.color.colorSelected);
                }
                else{
                    tempItemView.setBackgroundResource(R.color.colorDefault);
                }
            }
        }
    });
    return myViewHolder;
}

ОБНОВИТЬ

Вышеуказанный метод может испортить некоторые атрибуты по умолчанию элемента itemView, в моем случае я использовал CardView, а угловой радиус карты удалялся по клику.

Лучшее решение:

//instance variable
List<CardView>cardViewList = new ArrayList<>();

public class MyViewHolder extends RecyclerView.ViewHolder {
        CardView cardView; //THIS IS MY ROOT VIEW
        ...

        public MyViewHolder(View view) {
            super(view);
            cardView = view.findViewById(R.id.row_item_card);
            ...
        }
}

@Override
    public void onBindViewHolder(final MyViewHolder holder, int position) {
        final OurLocationObject locationObject = locationsList.get(position);
        ...

        cardViewList.add(holder.cardView); //add all the cards to this list

        holder.cardView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //All card color is set to colorDefault
                for(CardView cardView : cardViewList){
                cardView.setCardBackgroundColor(context.getResources().getColor(R.color.colorDefault));
                }
                //The selected card is set to colorSelected
                holder.cardView.setCardBackgroundColor(context.getResources().getColor(R.color.colorSelected));
            }
        });
}

ОБНОВЛЕНИЕ 2 - ВАЖНО

Метод onBindViewHolder вызывается несколько раз, а также каждый раз, когда пользователь прокручивает представление из поля зрения и обратно! Это приведет к тому, что одно и то же представление будет добавлено в список несколько раз, что может вызвать проблемы и незначительную задержку при выполнении кода!

Чтобы исправить это, измените

cardViewList.add(holder.cardView);

в

if (!cardViewList.contains(holder.cardView)) {
    cardViewList.add(holder.cardView);
}

Ответ 3

Я могу предложить это решение, которое я использовал в своем приложении. Я поместил этот код onTouchListener в свой конструктор класса ViewHolder. itemView - аргумент конструктора. Обязательно используйте return false для этого метода, потому что это необходимо для работы OnClickListener

itemView.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if(event.getAction() == MotionEvent.ACTION_DOWN)
        {
            v.setBackgroundColor(Color.parseColor("#f0f0f0"));
        }
        if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL)
        {
            v.setBackgroundColor(Color.TRANSPARENT);
        }
        return false;
    }
});

Ответ 4

Создать графический файл в Drawable foloder   

<item android:drawable="@color/SelectedColor" android:state_pressed="true"></item>
<item android:drawable="@color/SelectedColor" android:state_selected="true"></item>
<item android:drawable="@color/DefultColor"></item>

И в xml файле

android:background="@drawable/Drawable file"

В RecyclerView onBindViewHolder

holder.button.setSelected(holder.button.isSelected()?true:false);

Как кнопка переключения

Ответ 5

Если вы используете kotlin, это действительно просто.

В вашем классе RecyclerAdapter

userV.invalidateRecycler()

holder.card_User.setCardBackgroundColor(Color.parseColor("#3eb1ae").withAlpha(60))

В вашем фрагменте или деятельности

 override fun invalidateRecycler() {
    if (v1.recyclerCompanies.childCount > 0) {
        v1.recyclerCompanies.childrenRecursiveSequence().iterator().forEach { card ->
            if (card is CardView) {
                card.setCardBackgroundColor(Color.WHITE)
            }
        }
    }
}

Ответ 6

Мое решение:

public static class SimpleItemRecyclerViewAdapter
        extends RecyclerView.Adapter<SimpleItemRecyclerViewAdapter.ViewHolder> {

    private final MainActivity mParentActivity;
    private final List<DummyContent.DummyItem> mValues;
    private final boolean mTwoPane;
    private static int lastClickedPosition=-1;
    **private static View viewOld=null;**
    private final View.OnClickListener mOnClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            DummyContent.DummyItem item = (DummyContent.DummyItem) view.getTag();
            if (mTwoPane) {
                Bundle arguments = new Bundle();
                arguments.putString(ItemDetailFragment.ARG_ITEM_ID, item.id);
                ItemDetailFragment fragment = new ItemDetailFragment();
                fragment.setArguments(arguments);
                mParentActivity.getSupportFragmentManager().beginTransaction()
                        .replace(R.id.item_detail_container, fragment)
                        .commit();
            } else {
                Context context = view.getContext();
                Intent intent = new Intent(context, ItemDetailActivity.class);
                intent.putExtra(ItemDetailFragment.ARG_ITEM_ID, item.id);

                context.startActivity(intent);
            }

            **view.setBackgroundColor(mParentActivity.getResources().getColor(R.color.SelectedColor));
            if(viewOld!=null)
                viewOld.setBackgroundColor(mParentActivity.getResources().getColor(R.color.DefaultColor));
            viewOld=view;**
        }
    };

viewOld имеет null в начале, затем указывает на последнее выбранное представление. С помощью onClick вы изменяете фон выбранного вида и переопределяете фон предпоследнего выбранного вида. Просто и функционально.

Ответ 7

Добавить клик для просмотра элементов в .onBindViewHolder() вашего адаптера RecyclerView. получить текущую выбранную позицию и изменить цвет на .setBackground() для ранее выбранного и текущего элемента

Ответ 8

Создайте селектор в папку Drawable:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"> 
<item android:state_pressed="true">
   <shape>
         <solid android:color="@color/blue" />
   </shape>
</item>

<item android:state_pressed="false">
    <shape>
       <solid android:color="@android:color/transparent" />
    </shape>
</item>
</selector>

Добавьте свойство в свой xml (где вы объявляете RecyclerView):

android:background="@drawable/selector"

Ответ 9

Самый простой способ с моей стороны - добавить переменную в adapterPage в качестве последней нажатой позиции.

in onBindViewHolder вставляет этот код, который проверяет последнюю сохраненную позицию, соответствующую положению загрузки Константы - это класс, в котором я объявляю свои глобальные переменные

if(Constants.LAST_SELECTED_POSITION_SINGLE_PRODUCT == position) {

    //change the view background here
    holder.colorVariantThumb.setBackgroundResource(R.drawable.selected_background);
}

//on view click you store the position value and notifyItemRangeChanged will 
// call the onBindViewHolder and will check the condition

holder.itemView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view){
        Constants.LAST_SELECTED_POSITION_SINGLE_PRODUCT=position;
        notifyItemRangeChanged(0, mColorVariants.size());
    } 
});

Ответ 10

Мне удалось сделать это из моей Activity, где я устанавливаю свой Rv, а не из адаптера

Если кому-то нужно сделать что-то подобное здесь, код

В этом случае цвет меняется на logClick

           @Override
        public void onLongClick(View view, int position) {
            Toast.makeText(UltimasConsultasActivity.this, "Item agregado a la lista de mails",
                    Toast.LENGTH_SHORT).show();

            sendMultipleMails.setVisibility(View.VISIBLE);
            valueEmail.setVisibility(View.VISIBLE);
            itemsSeleccionados.setVisibility(View.VISIBLE);

            listaEmails.add(superListItems.get(position));
            listaItems ="";
            NameOfyourRecyclerInActivity.findViewHolderForAdapterPosition(position).NameOfYourViewInTheViewholder.setBackgroundColor((Color.parseColor("#336F0D")));

            for(int itemsSelect = 0; itemsSelect <= listaEmails.size() -1; itemsSelect++){

             listaItems  +=  "*"+listaEmails.get(itemsSelect).getDescripcion() + "\n";
            }

            itemsSeleccionados.setText("Items Seleccionados : "+  "\n" + listaItems);


        }


    }));

Ответ 12

Я получил это так

public void onClick(View v){
        v.findViewById(R.id.textView).setBackgroundColor(R.drawable.selector_row);
 }

Спасибо

Ответ 13

То, что я сделал для достижения этой цели, на самом деле принимало статическую переменную, чтобы сохранить последнее нажатое положение элемента в RecyclerView, а затем уведомить адаптер, чтобы обновить макет в позиции в последнем нажатом положении, т.е. notifyItemChanged (lastClickedPosition) всякий раз, когда новая позиция щелчок. Вызов notifyDataSetChanged() на весь макет очень дорогостоящий и неосуществимый, поэтому сделать это только для одной позиции намного лучше.

Вот код для этого:

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

private String android_versionnames[];
private Context mContext;
private static lastClickedPosition = -1; // Variable to store the last clicked item position


    public RecyclerDataAdapter(Context context,String android_versionnames[]){
        this.android_versionnames = android_versionnames;
        this.mContext = context;
        }
    }


    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(mContext).inflate(R.layout.row_layout,
                parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(final ViewHolder holder, int position) {
        holder.tv1.setText(android_versionnames[position]);    
        holder.itemView.setBackgroundColor(mContext.getResources().
        getColor(R.color.cardview_light_background));
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {                    
            v.setBackgroundColor(mContext.getResources().
            getColor(R.color.dark_background));
                if (lastClickedPosition != -1)
                    notifyItemChanged(lastClickedPosition);
                lastClickedPosition = position;
            }
        });
    }


    @Override
    public int getItemCount() {
        return android_versionnames.length;
    }


    public class ViewHolder extends RecyclerView.ViewHolder {
        private TextView tv1;

        public ViewHolder(final View itemView) {
            super(itemView);
            tv1=(TextView)itemView.findViewById(R.id.txtView1);
        }
    }
}

Таким образом, мы будем фактически обновлять только предназначенный элемент и не перезапускать ненужные обновления для элементов, которые даже не были изменены.