Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle click-event in RecyclerView.ItemDecoration?

I have a RecyclerView (with LinearLayoutManager) and a custom RecyclerView.ItemDecoration for it.

Let's say, I want to have buttons in the decoration view (for some reason..).

I inflate the layout with button, it draws properly. But I can't make the button clickable. If I press on it, nothing happening(it stays the same, no pressing effect) and onClick event is not firing.

The structure of ItemDecoration layout is

<LinearLayout>
  <TextView/>
  <Button/>
</LinearLayout>

And I'm trying to set listener in ViewHolder of the decoration

class ItemDecorationHolder extends RecyclerView.ViewHolder {
    public TextView header;
    public Button button;

    public HeaderHolder(View itemView) {
        super(itemView);

        header = (TextView)itemView.findViewById(R.id.header);
        button = (Button)itemView.findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //.. Show toast, etc.
            }
        });
    }
}

And i'm drawing the decoration in onDrawOver method. (actually, I'm modifying this codebase: https://github.com/edubarr/header-decor )

Any ideas? Is it doable?

Thanks!

like image 995
Konstantin Loginov Avatar asked Jun 28 '15 17:06

Konstantin Loginov


People also ask

How to handle click event on RecyclerView?

Update the ViewHolder to take in onClick() as a parameter. In the initializer, call setOnClickListener{} on the itemView . That's it! Your RecyclerView is now responsive so time to get your click on!


2 Answers

While the real header is scroll off the screen, the visible one is drawing on canvas directly ,not like a normal interactive widget.

You have these options

  1. Override RecyclerView.onInterceptTouchEvent(), though with some invasiveness so I prefer the next one.
  2. Make use of RecyclerView.addOnItemTouchListener(), remember the motion event argument has been translated into RecyclerView's coordinate system.
  3. Use a real header view, but that will go a little far I think.

If you take option 1/2, Button.setPressed(true) and redraw the header will have a visual press effect.

like image 58
Neil Avatar answered Oct 17 '22 15:10

Neil


In addition to what Neil said, the answer here might help. Passing MotionEvents from RecyclerView.OnItemTouchListener to GestureDetectorCompat

And then you just need to calculate the height of the header and see if the click falls onto that header view and handle the event yourself.

private class RecyclerViewOnGestureListener extends GestureDetector.SimpleOnGestureListener {
    @Override
    public boolean onSingleTapConfirmed(MotionEvent e) {
        float touchY = e.getY();



        ALLog.i(this, "Recyclerview single tap confirmed y: " + touchY);
        //mGroupHeaderHeight is the height of the header which is used to determine whether the click is inside of the view, hopefully it's a fixed size it would make things easier here 
        if(touchY < mGroupHeaderHeight) {
            int itemAdapterPosition = mRecyclerView.getLayoutManager().getPosition(mRecyclerView.findChildViewUnder(0, mGroupHeaderHeight));

            //Do stuff here no you have the position of the item that's been clicked
            return true;
        }
        return super.onSingleTapConfirmed(e);

    }

    @Override
    public boolean onDown(MotionEvent e) {
        float touchY = e.getY();

        if(touchY < mGroupHeaderHeight) {
            return true;
        }
        return super.onDown(e);
    }

    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        float touchY = e.getY();

        if(touchY < mGroupHeaderHeight) {
            return true;
        }
        return super.onSingleTapUp(e);
    }
}
like image 2
Alex Avatar answered Oct 17 '22 15:10

Alex