Search code examples
androidandroid-recyclerviewontouchlistener

Highlight selected item in RecyclerView WHILE clicking


I got a RecyclerView and I worked it out how to highlight items when they get clicked and did like they tell here.

But this will highlight the item after it got clicked. I would like to have something like in a normal ListView. So the item should be highlighted while clicking. This is why I used OnTouchListener instead.

@Override
    public boolean onTouch(View v, MotionEvent event) {
        int adapterPosition = getAdapterPosition();
        if (adapterPosition == RecyclerView.NO_POSITION) return false;

        adapter.notifyItemChanged(adapter.getSelectedPos());
        adapter.setSelectedPos(adapterPosition);
        adapter.notifyItemChanged(adapter.getSelectedPos());

        if(event.getAction() == MotionEvent.ACTION_UP){
            clicks.onItemSelected(adapterPosition);
            return true;
        }

        return false;
    }

But my Problem is, that I also want to know when the user moves his finger up, so I can do what I want when it is clicked. But unfortunately this does not work. How can I achieve this?


Solution

  • The code you provided, I don't think it is right approach to just highlight the selected item. Your code will notify items unnecessary many times.

    This can be done with a selector drawable. As there are many answers which guide, how to use a selector background.

    But here is the problem

    selectableItemBackground just works for the touch, not selection. So here is a hack.

    We will set foreground as ?selectableItemBackground and a custom background selector on same view.

    I created a sample which fulfill your requirement.

    • First make a background selector which sets transparent color if deactivated, and a color when activated.

    activated_color_selector.xml

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:state_activated="true">
            <color android:color="@color/colorPrimary"/>
        </item>
        <item>
            <color android:color="@android:color/transparent"/>
        </item>
    </selector>
    
    • Use this selector as your item's background. Also set foreground as ?selectableItemBackground.

    row.xml

    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/ll"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:background="@drawable/activated_color_selector"
        android:foreground="?selectableItemBackground">
    
        // other views inside
    
    </LinearLayout>
    
    • Your model class will hold selected boolean.

    Model.java

    public class BaseModel extends BaseObservable {
        private boolean selected;
        // setter getter
    }
    
    • Attach model selected field to the View. Also invert selected field when clicked.

    Inside RecyclerView adapter

    @Override
    public void onBindViewHolder(MyViewHolder holder, final int position) {
        final BaseModel model = list.get(position);
        holder.linearLayout.setActivated(model.isSelected());
        holder.linearLayout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                model.setSelected(!model.isSelected());
                notifyItemChanged(position);
            }
        });
    }
    

    All done!