Search code examples
androidandroid-recyclerviewandroid-cardviewonitemclicklistenercardview

Put RecyclerView in front of Image


I am building an App that uses RecyclerView and CardView. Since RecyclerView doesn’t have an onItemClickListener method I found one class implementation that does this and was able to insert this class in my project.

In each card I am putting one imageView (I am using Glide to load images) and a couple of TextViews. When the TextView was below the image I was able to use the onItemClickListener Perfectly, but I decided to put the text in front of the image inside a RelativeLayout with a black transparent background.

The problem is that after this change the onItemClickListener stopped working. The images occupy the whole cardView and the TextView is in front of it. By clicking on any of these elements the method doesn’t work. I think that I need to bring the recyclerView to the front of the activity but I don’t know how to do that. I tried to use recyclerView.bringToFront() but it didn’t work.

This is the card before (the click listener was working when clicking on the white area):

enter image description here

And this is the card now (the click listener doesn't work when I click anywhere):

enter image description here

This is my ItemClickSupport class:

public class ItemClickSupport {
    private final RecyclerView mRecyclerView;
    private OnItemClickListener mOnItemClickListener;
    private OnItemLongClickListener mOnItemLongClickListener;
    private View.OnClickListener mOnClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (mOnItemClickListener != null) {
                RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
                mOnItemClickListener.onItemClicked(mRecyclerView, holder.getAdapterPosition(), v);
            }
        }
    };
    private View.OnLongClickListener mOnLongClickListener = new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(View v) {
            if (mOnItemLongClickListener != null) {
                RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
                return mOnItemLongClickListener.onItemLongClicked(mRecyclerView, holder.getAdapterPosition(), v);
            }
            return false;
        }
    };
    private RecyclerView.OnChildAttachStateChangeListener mAttachListener
            = new RecyclerView.OnChildAttachStateChangeListener() {
        @Override
        public void onChildViewAttachedToWindow(View view) {
            if (mOnItemClickListener != null) {
                view.setOnClickListener(mOnClickListener);
            }
            if (mOnItemLongClickListener != null) {
                view.setOnLongClickListener(mOnLongClickListener);
            }
        }

        @Override
        public void onChildViewDetachedFromWindow(View view) {

        }
    };

    private ItemClickSupport(RecyclerView recyclerView) {
        mRecyclerView = recyclerView;
        mRecyclerView.setTag(R.id.item_click_support, this);
        mRecyclerView.addOnChildAttachStateChangeListener(mAttachListener);
    }

    public static ItemClickSupport addTo(RecyclerView view) {
        ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
        if (support == null) {
            support = new ItemClickSupport(view);
        }
        return support;
    }

    public static ItemClickSupport removeFrom(RecyclerView view) {
        ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
        if (support != null) {
            support.detach(view);
        }
        return support;
    }

    public ItemClickSupport setOnItemClickListener(OnItemClickListener listener) {
        mOnItemClickListener = listener;
        return this;
    }

    public ItemClickSupport setOnItemLongClickListener(OnItemLongClickListener listener) {
        mOnItemLongClickListener = listener;
        return this;
    }

    private void detach(RecyclerView view) {
        view.removeOnChildAttachStateChangeListener(mAttachListener);
        view.setTag(R.id.item_click_support, null);
    }

    public interface OnItemClickListener {

        void onItemClicked(RecyclerView recyclerView, int position, View v);
    }

    public interface OnItemLongClickListener {

        boolean onItemLongClicked(RecyclerView recyclerView, int position, View v);
    }
}

And this is me calling it from my Activity:

ItemClickSupport.addTo(recyclerView).setOnItemClickListener(new ItemClickSupport.OnItemClickListener() {
            @Override
            public void onItemClicked(RecyclerView recyclerView, int position, View v) {

                Intent intent = new Intent(getBaseContext(), MovieDetails.class);
                intent.putExtra("movie_name", movies.get(position).getTitle());
                intent.putExtra("movie_rating", movies.get(position).getVoteAverage().toString());
                intent.putExtra("movie_description", movies.get(position).getOverview());
                intent.putExtra("movie_cover", movies.get(position).getPosterPath());
                intent.putExtra("movie_date", movies.get(position).getReleaseDate());
                intent.putExtra("movie_language", movies.get(position).getOriginalLanguage());
                intent.putExtra("movie_backdrop", movies.get(position).getBackdropPath());
                //intent.putExtra("album_name", albumList.get(position).getName());
                //intent.putExtra("album_thumbnail", Integer.toString(albumList.get(position).getThumbnail()));
                //intent.putExtra("number_songs", Integer.toString(albumList.get(position).getNumOfSongs()));

                startActivity(intent);
            }
        });

This is my Adapter:

public class MoviesAdapter extends RecyclerView.Adapter<MoviesAdapter.MyViewHolder> {

    private Context mContext;
    private List<MovieItem> movieList;

    public class MyViewHolder extends RecyclerView.ViewHolder {
        public TextView title, count;
        public ImageView thumbnail, overflow, star1, star2, star3, star4, star5;

        public MyViewHolder(View view) {
            super(view);
            title = (TextView) view.findViewById(R.id.title);
            count = (TextView) view.findViewById(R.id.count);
            thumbnail = (ImageView) view.findViewById(R.id.thumbnail);
            star1 = (ImageView) view.findViewById(R.id.rating_image1);
            star2 = (ImageView) view.findViewById(R.id.rating_image2);
            star3 = (ImageView) view.findViewById(R.id.rating_image3);
            star4 = (ImageView) view.findViewById(R.id.rating_image4);
            star5 = (ImageView) view.findViewById(R.id.rating_image5);
            //overflow = (ImageView) view.findViewById(R.id.overflow);
        }
    }


    public MoviesAdapter(Context mContext, List<MovieItem> movieList) {
        this.mContext = mContext;
        this.movieList = movieList;
    }

    @Override
    public MoviesAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.album_card, parent, false);

        return new MyViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(final MoviesAdapter.MyViewHolder holder, int position) {
        MovieItem movie = movieList.get(position);
        holder.title.setText(movie.getTitle());
        holder.count.setText("R: " + movie.getVoteAverage().toString() + "/10");

        Glide.with(mContext).load("https://image.tmdb.org/t/p/w500" + movie.getPosterPath()).into(holder.thumbnail);

    }


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

Solution

  • I managed to solve my problem by doing what Sahil suggested me to. I put the onClickListener on the image instead of the recycler view. To do that I had to put the code inside my Adapter in the onBindViewHolder method (I didn't know I could do that).

    It was something like this: (I had to declare the variable int position as final in order to access it in the onClickListener and to set the flag Intent.FLAG_ACTIVITY_NEW_TASK because I was starting another Activity from outside an Activity.

     @Override
    public void onBindViewHolder(final MyViewHolder holder, final int position) {
    
    holder.thumbnail.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Intent intent = new Intent(mContext, MovieDetails.class);
                    intent.putExtra("movie_name", movieList.get(position).getTitle());
                    intent.putExtra("movie_rating", movieList.get(position).getVoteAverage().toString());
                    intent.putExtra("movie_description", movieList.get(position).getOverview());
                    intent.putExtra("movie_cover", movieList.get(position).getPosterPath());
                    intent.putExtra("movie_date", movieList.get(position).getReleaseDate());
                    intent.putExtra("movie_language", movieList.get(position).getOriginalLanguage());
                    intent.putExtra("movie_backdrop", movieList.get(position).getBackdropPath());
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    //intent.putExtra("album_name", albumList.get(position).getName());
                    //intent.putExtra("album_thumbnail", Integer.toString(albumList.get(position).getThumbnail()));
                    //intent.putExtra("number_songs", Integer.toString(albumList.get(position).getNumOfSongs()));
    
                    mContext.startActivity(intent);
                }
            });
    }