Getting position of View in onCreateViewHolder

24,319

Solution 1

You cannot use the position parameter of onBindViewHolder in a callback. If a new item is added above, RecyclerView will not rebind your item so the position is obsolete. Instead, RecyclerView provides a getAdapterPosition method on the ViewHolder.

@Override
public ViewHolder onCreateViewHolder(final ViewGroup parent, int viewType) {
    final View view = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.single_line_row, parent, false);
    final ViewHolder holder = new ViewHolder(view);
    view.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            final int position = holder.getAdapterPosition();
            if (position != RecyclerView.NO_POSITION) {
                remove(mCommentList.get(position));
            }
        }
    });
    return holder;
}

I've added position != RecyclerView.NO_POSITION check because when item is removed, RecyclerView will fade out the View so it may still be clicked by the user but its adapter position will return NO_POSITION.

Solution 2

you can create a method to update position in your class.

in my case I need to attach watcher and get the position to update arraylist. here is the example:

class DodolWatcher bla bla {
    private var position: Int = 0
    fun updatePosition(pos:Int)
    {
      position = pos
    }

    override fun onTextChanged(charSequence: CharSequence, i: Int, i2: Int, i3: Int) {
    Log.d("test", position.toString())
    }

}

and in your onCreateViewHolder you can attach watcher to edittext

 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RVPaymentMethodAdapter.ViewHolder {
     ....
     bla bla
     ....
     theWatcher = DodolWatcher() <-- this is the trick
     amount.addTextChangedListener(theWatcher)
 }

and you will able to update position in your bindViewHolder like this:

override fun onBindViewHolder(viewHolder: RVPaymentMethodAdapter.ViewHolder, position: Int) {
     theWatcher.updatePosition(viewHolder.adapterPosition)  <-- this is the trick
 }
Share:
24,319

Related videos on Youtube

Thomas Mohr
Author by

Thomas Mohr

Updated on July 09, 2022

Comments

  • Thomas Mohr
    Thomas Mohr almost 2 years

    I am using a RecyclerView with a single row layout with an ImageView and a TextView.

    I want to implement a OnClickListener for the View and not for seperate ViewHolder objects. How can i get the position of the view in the Adapter?

    Right now i'm deleting comments on click, but i cannot select the clicked View. I added a TODO in the appropriate line.

    public class CommentAdapter extends RecyclerView.Adapter<CommentAdapter.ViewHolder> {
    
        /** List of Comment objects */
        private List<Comment> mCommentList;
    
        /** Database with Comment objects */
        private CommentsDataSource mDataSource;
    
        /**
         * Construcutor for CommentAdapter
         *
         * @param commentList   List of Comment objects
         * @param dataSource    Database with Comment objects
         */
        public CommentAdapter(List<Comment> commentList, CommentsDataSource dataSource) {
            this.mCommentList = commentList;
            this.mDataSource = dataSource;
        }
    
        /**
         * Add Comment objects to RecyclerView
         *
         * @param position  The position where the Comment object is added
         * @param comment   Comment Object
         */
        public void add(int position, Comment comment) {
            mCommentList.add(position, comment);
            notifyItemInserted(position);
        }
    
        /**
         * Remove Comment objects from RecyclerView
         *
         * @param comment Comment Object
         */
        public void remove(Comment comment) {
            int position = mCommentList.indexOf(comment);
            // Avoid double tap remove
            if (position != -1) {
                mCommentList.remove(position);
                mDataSource.deleteComment(comment);
                notifyItemRemoved(position);
            }
        }
    
        @Override
        public ViewHolder onCreateViewHolder(final ViewGroup parent, int viewType) {
            final View view = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.single_line_row, parent, false);
            view.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    // TODO get position
                    remove(mCommentList.get(getItemCount() - 1));
                }
            });
            return new ViewHolder(view);
        }
    
        @Override
        public void onBindViewHolder(ViewHolder holder, int position) {
            final Comment comment = mCommentList.get(position);
            holder.comment.setText(comment.getComment());
        }
    
        @Override
        public int getItemCount() {
            return mCommentList.size();
        }
    
        public static class ViewHolder extends RecyclerView.ViewHolder {
    
            /** ImageView icon */
            public ImageView icon;
    
            /** TextView comment */
            public TextView comment;
    
            /**
             * Constructor for ViewHolder
             *
             * @param itemView Layout for each row of RecyclerView
             */
            public ViewHolder(final View itemView) {
                super(itemView);
                icon = (ImageView) itemView.findViewById(R.id.icon);
                comment = (TextView) itemView.findViewById(R.id.comment);
            }
        }
    }
    
    • pskink
      pskink about 9 years
      you should really set your OnClickListener in ViewHolder(final View itemView) constructor, in that case ViewHolder should implement OnClickListener
  • Axay Prajapati
    Axay Prajapati about 7 years
    Whatever I click, I am getting position -1 (RecyclerView.NO_POSITION), what will be the issue?
  • starkej2
    starkej2 almost 7 years
    Don't do this - it will make the Adapter create a new view for every item in your list rather than recycle them, since it will think they are all different types.
  • Irfan
    Irfan about 5 years
    bad way to do it.
  • Neph
    Neph over 4 years
    Does it matter if you set the OnClickListener on the view or the holder? I linked it to the holder first, then changed it to the view after seeing this answer but it didn't seem to actually make a difference - at least not with a RecycleView that wasn't scrollable (not enough items for that).