You may use a Facade view to deal with this issue. By creating LinearLayout within and LinearLayout you can choose what deals with what clicks. So for how to handle long clicks setOnCreateContextMenuListener, short clicks and clicks on items within the view.
Here is an example layout, take note of focusable/clickable params.
Layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="false"
android:focusable="false"
>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/showClickable"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:focusable="true"
android:background="?android:attr/selectableItemBackground"
>
<TextView
android:text="TextView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="@+id/itemShowTitle"
android:layout_weight="1"
/>
<Button
android:id="@+id/buttonWorthClicking"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="button worth clicking"/>
</LinearLayout>
</LinearLayout>
Then we need the ViewHolder that passes along or deals with clicks as needed
public class ShowsRecyclerViewAdapter extends RecyclerView.Adapter<ShowsRecyclerViewAdapter.ViewHolder> {
public ShowsRecyclerViewAdapter(List<Show> shows) {
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.show_list_item, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.itemShowTitle.setText("" + position);
}
@Override
public int getItemCount() {
return 10;
}
static class ViewHolder extends RecyclerView.ViewHolder
implements View.OnClickListener, View.OnCreateContextMenuListener {
final TextView itemShowTitle;
final Button buttonWorthClicking;
ViewHolder(final View itemView) {
super(itemView);
itemView.setOnClickListener(this);
itemShowTitle = (TextView) itemView.findViewById(R.id.itemShowTitle);
buttonWorthClicking = (Button) itemView.findViewById(R.id.buttonWorthClicking);
setViewFacade(itemView);
itemView.setOnCreateContextMenuListener(this);
}
/**
* Because the layout is nested to for the ripple we build a facade to pass along clicks
*/
private void setViewFacade(final View itemView) {
View facedForClicks = itemView.findViewById(R.id.showClickable);
facedForClicks.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// pass along the short click
ViewHolder.this.onClick(itemView);
}
});
facedForClicks.setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() {
@Override
public void onCreateContextMenu(ContextMenu contextMenu, View view, ContextMenu.ContextMenuInfo contextMenuInfo) {
// no-op but passes up to the ViewHolder
}
});
buttonWorthClicking.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("one-off", "the button was clicked");
}
});
}
@Override
public void onClick(View v) {
Log.d("one-off", "short click on item");
}
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo contextMenuInfo) {
Log.d("one-off", "long click on item");
}
}
}
I made a branch on my Podcast Player project on github you can see a working example.
Class
XML
branch