RecyclerView OnClickListener using interface

后端 未结 11 742
清歌不尽
清歌不尽 2020-12-01 09:49

I use RecyclerView adapter to display data inside an activity, I want to implement onClickListener inside the activity, currently, I am setting

相关标签:
11条回答
  • 2020-12-01 10:05

    very simple and clean solution is:

      create a class with the name of RecyclerTouchListener:
    
        public class RecyclerTouchListener implements RecyclerView.OnItemTouchListener {
    
            private GestureDetector gestureDetector;
            private ClickListener clickListener;
    
            public RecyclerTouchListener(Context context, final RecyclerView recyclerView, final ClickListener clickListener) {
                this.clickListener = clickListener;
                gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
                    @Override
                    public boolean onSingleTapUp(MotionEvent e) {
                        return true;
                    }
    
                    @Override
                    public void onLongPress(MotionEvent e) {
                        View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
                        if (child != null && clickListener != null) {
                            clickListener.onLongClick(child, recyclerView.getChildPosition(child));
                        }
                    }
                });
            }
    
            @Override
            public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
    
                View child = rv.findChildViewUnder(e.getX(), e.getY());
                if (child != null && clickListener != null && gestureDetector.onTouchEvent(e)) {
                    clickListener.onClick(child, rv.getChildPosition(child));
                }
                return false;
            }
    
            @Override
            public void onTouchEvent(RecyclerView rv, MotionEvent e) {
            }
    
            @Override
            public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
    
            }
    
            public interface ClickListener {
                void onClick(View view, int position);
    
                void onLongClick(View view, int position);
            }
        }
    

    in your recyclerview activity:

    recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getApplicationContext(), recyclerView, new RecyclerTouchListener.ClickListener() {
                @Override
                public void onClick(View view, int position) {
                    speech(countries_list_code[position]);
                }
    
                @Override
                public void onLongClick(View view, int position) {
    
                }
            }));
    
    0 讨论(0)
  • 2020-12-01 10:06

    RecyclerView widget only has 2 useful listeners for this scenario:

    • RecyclerView.OnChildAttachStateChangeListener - covered here
    • RecyclerView.OnItemTouchListener - the one that I will be covering

    the code is inspired by TouchEvents sample related to Accessibility, and works in Activity/Fragment without setting any listeners in the Adapter

    recyclerView.addOnItemTouchListener(object : RecyclerView.SimpleOnItemTouchListener() {
        var downTouch = false
        override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean {
            when (e.action) {
                MotionEvent.ACTION_DOWN -> downTouch = true
                MotionEvent.ACTION_UP -> if (downTouch) {
                    downTouch = false
                    recyclerView.findChildViewUnder(e.x, e.y)?.let {
                        val position = rv.getChildAdapterPosition(it)
                        Toast.makeText(rv.context, "clicked on $position", Toast.LENGTH_SHORT)
                            .show()
                    }
                }
                else -> downTouch = false
            }
            return super.onInterceptTouchEvent(rv, e)
        }
    })
    
    0 讨论(0)
  • 2020-12-01 10:14

    Create an interface for the adapter class

    private OnItemClickListener mListener;
    
    public CustomAdapter(List<Listdata> listdata, OnItemClickListener listener) {
        mListener = listener;
        ...
        ...
    }
    
    private class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
    
        ViewHolder(View view) {
            ...
            ...
            view.setOnClickLister(this);
        }
    
        @override
        public void onClick(View v) {
            mListener.onAdapterItemClick(getAdapterPosition())
        }
    }
    
    interface OnItemClickListener {
        void onAdapterItemClick(int position);
    }
    

    Let the activity implement the interface

    public class CustomListActivity extends AppCompatActivity implements OnItemClickListener {
    
    ...
    ...
    
    @override
    public void onAdapterItemClick(int position) {
        Toast.makeText(activity, "clicked on " +position, Toast.LENGTH_SHORT).show();
    }
    

    There is another way of doing this, check out this implementation

    0 讨论(0)
  • 2020-12-01 10:21

    Personally, I like to handle this via RxJava subjects:

    A Subject is a sort of bridge or proxy that is available in some implementations of ReactiveX that acts both as an observer and as an Observable. Because it is an observer, it can subscribe to one or more Observables, and because it is an Observable, it can pass through the items it observes by re-emitting them, and it can also emit new items.

    For more info read Understanding RxJava Subject — Publish, Replay, Behavior and Async Subject.

    in Adapter:

    public static PublishSubject<MyData> onClickSubject = PublishSubject.create();
    

    ViewHolder:

    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        .
        .
        .
    
        @Override
        public void onClick(View view) {
            onClickSubject.onNext(getItem(getAdapterPosition()));
        }
    }
    

    Add your disposables to a CompositeDisposable and dispose them in onDestroy():

    private CompositeDisposable compositeDisposable = new CompositeDisposable();
    

    in onCreate():

    compositeDisposable.add(MyAdapter.onClickSubject.subscribe(myData -> {
        //do something here
    }));
    

    in onDestroy():

    compositeDisposable.dispose();
    

    Note:

    1. getItem() is a method of androidx.recyclerview.widget.ListAdapter and androidx.paging.PagedListAdapter if you are extending RecyclerView.Adapter you can get item from your data list by position.

    2. to use Disposables you need RxJava2 or above

    0 讨论(0)
  • 2020-12-01 10:22

    You need to check this tutorial here for better understanding on how you can achieve the behaviour that you want.

    In case of handling the onClickListener from your activity you need to work based on a callback implementation with an interface. Pass the interface from the activity to your adapter and then call the callback function from your adapter when some items are clicked.

    Here's a sample implementation from the tutorial.

    Let us first have the interface.

    public interface OnItemClickListener {
        void onItemClick(ContentItem item);
    }
    

    You need to modify your adapter to take the listener as the parameter like the one stated below.

    private final List<ContentItem> items;
    private final OnItemClickListener listener;
    
    public ContentAdapter(List<ContentItem> items, OnItemClickListener listener) {
        this.items = items;
        this.listener = listener;
    }
    

    Now in your onBindViewHolder method, set the click listener.

    @Override public void onBindViewHolder(ViewHolder holder, int position) {
        holder.bind(items.get(position), listener);
    }
    
    public void bind(final ContentItem item, final OnItemClickListener listener) {
        ...
        itemView.setOnClickListener(new View.OnClickListener() {
            @Override public void onClick(View v) {
                listener.onItemClick(item);
            }
        });
    }
    

    Now setting the adapter in your RecyclerView.

    recycler.setAdapter(new ContentAdapter(items, new ContentAdapter.OnItemClickListener() {
        @Override public void onItemClick(ContentItem item) {
            Toast.makeText(getContext(), "Item Clicked", Toast.LENGTH_LONG).show();
        }
    }));
    

    So the whole adapter code looks like the following.

    public class ContentAdapter extends RecyclerView.Adapter<ContentAdapter.ViewHolder> {
    
        public interface OnItemClickListener {
            void onItemClick(ContentItem item);
        }
    
        private final List<ContentItem> items;
        private final OnItemClickListener listener;
    
        public ContentAdapter(List<ContentItem> items, OnItemClickListener listener) {
            this.items = items;
            this.listener = listener;
        }
    
        @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_item, parent, false);
            return new ViewHolder(v);
        }
    
        @Override public void onBindViewHolder(ViewHolder holder, int position) {
            holder.bind(items.get(position), listener);
        }
    
        @Override public int getItemCount() {
            return items.size();
        }
    
        static class ViewHolder extends RecyclerView.ViewHolder {
    
            private TextView name;
            private ImageView image;
    
            public ViewHolder(View itemView) {
                super(itemView);
                name = (TextView) itemView.findViewById(R.id.name);
                image = (ImageView) itemView.findViewById(R.id.image);
            }
    
            public void bind(final ContentItem item, final OnItemClickListener listener) {
                name.setText(item.name);
                Picasso.with(itemView.getContext()).load(item.imageUrl).into(image);
                itemView.setOnClickListener(new View.OnClickListener() {
                    @Override public void onClick(View v) {
                        listener.onItemClick(item);
                    }
                });
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题