How to highlight selected item in RecyclerView

I have used RecyclerView for showing thumbnails in my Image Editing app.Each item of its comprises of a ImageView(thumbnail) and a textView.In my application I want to highlight only current selected thumbnail when clicked.Gone through all the related posts on SO but couldn't find any better solution.

My Adapter Class

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

    private Context mContext;
    private List<Type> mDataSet;
    private Uri selectedPhoto;

    public enum Type {
        Original,
        Grayscale,
        Sepia,
        Contrast,
        Invert,
        Pixel,
        Sketch,
        Swirl,
        Brightness,
        Vignette
    }

    public FiltersAdapter(Context context, List<Type> dataSet, Uri selectedPhoto) {
        mContext = context;
        mDataSet = dataSet;
        this.selectedPhoto = selectedPhoto;
    }

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

    @Override
    public void onBindViewHolder(FiltersAdapter.ViewHolder holder, int position) {
        switch (mDataSet.get(position)) {
            case Original:
                holder.image.setImageResource(R.drawable.no_filter);
                break;
            case Grayscale:
                Picasso.with(mContext)
                        .load(R.drawable.no_filter)
                        .transform(new GrayscaleTransformation())
                        .into(holder.image);
                break;
            case Sepia:
                Picasso.with(mContext)
                        .load(R.drawable.no_filter)
                        .transform(new SepiaFilterTransformation(mContext))
                        .into(holder.image);
                break;
            case Contrast:
                Picasso.with(mContext)
                        .load(R.drawable.no_filter)
                        .transform(new ContrastFilterTransformation(mContext, 2.0f))
                        .into(holder.image);
                break;
            case Invert:
                Picasso.with(mContext)
                        .load(R.drawable.no_filter)
                        .transform(new InvertFilterTransformation(mContext))
                        .into(holder.image);
                break;
            case Pixel:
                Picasso.with(mContext)
                        .load(R.drawable.no_filter)
                        .transform(new PixelationFilterTransformation(mContext, 20))
                        .into(holder.image);
                break;
            case Sketch:
                Picasso.with(mContext)
                        .load(R.drawable.no_filter)
                        .transform(new SketchFilterTransformation(mContext))
                        .into(holder.image);
                break;
            case Swirl:
                Picasso.with(mContext)
                        .load(R.drawable.no_filter)
                        .transform(new SwirlFilterTransformation(mContext, 0.5f, 1.0f, new PointF(0.5f, 0.5f)))
                        .into(holder.image);
                break;
            case Brightness:
                Picasso.with(mContext)
                        .load(R.drawable.no_filter)
                        .transform(new BrightnessFilterTransformation(mContext, 0.5f))
                        .into(holder.image);
                break;
            case Vignette:
                Picasso.with(mContext)
                        .load(R.drawable.no_filter)
                        .transform(new VignetteFilterTransformation(mContext, new PointF(0.5f, 0.5f),
                                new float[]{0.0f, 0.0f, 0.0f}, 0f, 0.75f))
                        .into(holder.image);
                break;
            default:
                holder.image.setImageResource(R.drawable.no_filter);
                break;

        }
        holder.title.setText(mDataSet.get(position).name());
    }

    @Override
    public void onViewAttachedToWindow(ViewHolder holder) {
        super.onViewAttachedToWindow(holder);

    }

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

    @Override
    public int getItemViewType(int position) {
        return position;
    }

    static class ViewHolder extends RecyclerView.ViewHolder {

        public ImageView image;
        public TextView title;

        ViewHolder(View itemView) {
            super(itemView);
            image = (ImageView) itemView.findViewById(R.id.thumbnailImage);
            title = (TextView) itemView.findViewById(R.id.title);
        }


    }
}

Fragment Code

horizontalFilters = (RecyclerView) mView.findViewById(R.id.rvHorizontal);
    LinearLayoutManager horizontalLayoutManagaer
            = new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false);
    horizontalFilters.setLayoutManager(horizontalLayoutManagaer);

    List<Type> dataSet = new ArrayList<>();
    dataSet.add(Type.Original);
    dataSet.add(Type.Grayscale);
    dataSet.add(Type.Sepia);
    dataSet.add(Type.Contrast);
    dataSet.add(Type.Invert);
    dataSet.add(Type.Pixel);
    dataSet.add(Type.Sketch);
    dataSet.add(Type.Swirl);
    dataSet.add(Type.Brightness);
    dataSet.add(Type.Vignette);

    horizontalFilters.setAdapter(new FiltersAdapter(act, dataSet, selectedPhotoUri));

    horizontalFilters.addOnItemTouchListener(new RecyclerClick(act, horizontalFilters, new RecyclerClickListener() {
        @Override
        public void onClick(View view, int position) {
            switch (position){
                case 0:
                    photo.setImageDrawable(drawable);
                    break;
                case 1:
                    Picasso.with(act)
                            .load(selectedPhotoUri)
                            .transform(new GrayscaleTransformation())
                            .into(photo);
                    break;
                case 2:
                    Picasso.with(act)
                            .load(selectedPhotoUri)
                            .transform(new SepiaFilterTransformation(act))
                            .into(photo);
                    break;
                case 3:
                    Picasso.with(act)
                            .load(selectedPhotoUri)
                            .transform(new ContrastFilterTransformation(act, 2.0f))
                            .into(photo);
                    break;
                case 4:
                    Picasso.with(act)
                            .load(selectedPhotoUri)
                            .transform(new InvertFilterTransformation(act))
                            .into(photo);
                    break;
                case 5:
                    Picasso.with(act)
                            .load(selectedPhotoUri)
                            .transform(new PixelationFilterTransformation(act, 20))
                            .into(photo);
                    break;
                case 6:
                    Picasso.with(act)
                            .load(selectedPhotoUri)
                            .transform(new SketchFilterTransformation(act))
                            .into(photo);
                    break;
                case 7:
                    Picasso.with(act)
                            .load(selectedPhotoUri)
                            .transform(new SwirlFilterTransformation(act, 0.5f, 1.0f, new PointF(0.5f, 0.5f)))
                            .into(photo);
                    break;
                case 8:
                    Picasso.with(act)
                            .load(selectedPhotoUri)
                            .transform(new BrightnessFilterTransformation(act, 0.5f))
                            .into(photo);
                    break;
                case 9:
                    Picasso.with(act)
                            .load(selectedPhotoUri)
                            .transform(new VignetteFilterTransformation(act, new PointF(0.5f, 0.5f),
                                    new float[]{0.0f, 0.0f, 0.0f}, 0f, 0.75f))
                            .into(photo);
                    break;
                default:
                    photo.setImageDrawable(drawable);
                    break;
            }
        }

        @Override
        public void onLongClick(View view, int position) {

        }
    }));
}

Answers


Just add this below line in bindView

holder.itemView.setBackgroundColor(Color.parseColor("#000000"));

will work for you.

if you want to highlight selected item just do like below

set it global

int selectedPosition=-1;

inside onBindViewHolder-

public void onBindViewHolder(FiltersAdapter.ViewHolder holder, int position) {
if(selectedPosition==position)
  holder.itemView.setBackgroundColor(Color.parseColor("#000000"));
else
  holder.itemView.setBackgroundColor(Color.parseColor("#ffffff"));

holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                selectedPosition=position;
                notifyDataSetChanged();

            }
        });
}

Use background selector and set that in android:background property in the layout xml for the recyclerview item

background_selector.xml

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

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

recyclerview_item.xml (background_selector is set in android:background property)

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/background_selector"
    android:orientation="vertical"
    android:paddingBottom="8dp"
    android:paddingLeft="16dp"
    android:paddingRight="16dp"
    android:paddingTop="8dp">

And then the place where you get the click event you can set it as selected with the View function

view.setSelected(true)

You would have to implement the logic for when you want to unselect/select the item by storing the position of selected items


May be just use:

android:background="?attr/selectableItemBackground"

for root element at item xml?


update your enum to class first for flag

public class Type {
    public int type; // 0-Original,1-Grayscale,2-Sepia.... same as enum
    public int selected;
}

now in adapter

@Override
public void onBindViewHolder(FiltersAdapter.ViewHolder holder, int position) {
    int typeOfItem = mDataSet.get(position).type
    switch (mDataSet.get(position)) {
        case 0:
            holder.image.setImageResource(R.drawable.no_filter);
            break;
        case 1:
            Picasso.with(mContext)
                    .load(R.drawable.no_filter)
                    .transform(new GrayscaleTransformation())
                    .into(holder.image);
            break;
        case 2:
            Picasso.with(mContext)
                    .load(R.drawable.no_filter)
                    .transform(new SepiaFilterTransformation(mContext))
                    .into(holder.image);
            break;
        case 3:
            Picasso.with(mContext)
                    .load(R.drawable.no_filter)
                    .transform(new ContrastFilterTransformation(mContext, 2.0f))
                    .into(holder.image);
            break;
        case 4:
            Picasso.with(mContext)
                    .load(R.drawable.no_filter)
                    .transform(new InvertFilterTransformation(mContext))
                    .into(holder.image);
            break;
        case 5:
            Picasso.with(mContext)
                    .load(R.drawable.no_filter)
                    .transform(new PixelationFilterTransformation(mContext, 20))
                    .into(holder.image);
            break;
        case 6:
            Picasso.with(mContext)
                    .load(R.drawable.no_filter)
                    .transform(new SketchFilterTransformation(mContext))
                    .into(holder.image);
            break;
        case 7:
            Picasso.with(mContext)
                    .load(R.drawable.no_filter)
                    .transform(new SwirlFilterTransformation(mContext, 0.5f, 1.0f, new PointF(0.5f, 0.5f)))
                    .into(holder.image);
            break;
        case 8:
            Picasso.with(mContext)
                    .load(R.drawable.no_filter)
                    .transform(new BrightnessFilterTransformation(mContext, 0.5f))
                    .into(holder.image);
            break;
        case 9:
            Picasso.with(mContext)
                    .load(R.drawable.no_filter)
                    .transform(new VignetteFilterTransformation(mContext, new PointF(0.5f, 0.5f),
                            new float[]{0.0f, 0.0f, 0.0f}, 0f, 0.75f))
                    .into(holder.image);
            break;
        default:
            holder.image.setImageResource(R.drawable.no_filter);
            break;
    }
    holder.title.setText(mDataSet.get(position).name());
    if(mDataSet.get(position).selected == 0){
        holder.title.setTypeface(null, Typeface.BOLD);
    } else {
        holder.title.setTypeface(null,Typeface.NORMAL);
    }
}

not on every click or select update your list then call notifydatasetChanged() of adapter


Need Your Help

:except not working in before_filter in application controller. Routing problem?

ruby-on-rails routing before-filter

I have a before_filter in my application controller to keep a user's session alive (and log them out if a time out has been reached). This should be called on every action except /sessions/new and /

Cross-browser development

javascript css internet-explorer firefox cross-browser

I'm developing a web application for a new service, starting from Firefox 3.5.