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