Respond to buttons click in RecyclerView - android

I have a RecyclerView where the user has to click the elements to cast a vote to that specific player.
Current Layout
As it's not that much intuitive, I'd like to add Buttons on the right side of each element to let the user understand that he needs to click if he wants to cast a vote.
Question
How do I make a custom layout like that? Probably using a GridLayout? And mostly, how do I get the Button's element's position when the button (and it only) gets clicked?
Code
list_players.xml | http://pastebin.com/F7Ei07x9
two_line_list_item_horizontal.xml | http://pastebin.com/s8qvwqt4
CourseAdapter.java | http://pastebin.com/qZJeimfe

Replace your CoursesAdapter's onBindViewHolder with this.
#Override
public void onBindViewHolder(CoursesViewHolder holder, int position) {
Player player = mArrayCourses.get(position);
holder.name.setText(player.getName());
holder.counter.setText(String.valueOf(player.getCount()));
holder.voteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Do your work here
}
});
}

You can use LinearLayout to add button to your Recyclerview item by giving them weight.
You can handle onClicklistener of that button in ViewHolder class and you can get position of clicked button by getAdapterPosition() in ViewHolder class.
As per your request :
XML :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:weightSum="5">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="ABCD"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="A"/>
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Vote"/>
</LinearLayout>
Adapter :
public class Holder extends RecyclerView.ViewHolder{
Button btnVote;
public Holder(View itemView) {
super(itemView);
btnVote = (Button) itemView.findViewById(R.id.btn_vote);
btnVote.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//list.get(getAdapterPosition()); Use for get the data on selected item
}
});
}
}

Related

Recycler view not responding to clicks

My question is that I want a recycler view to respond to a click on the entire view, not individual clicks on each item that the recycler view has
<TextView
android:id="#+id/tv_amount_reviews"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="#{() -> viewModel.handleClick()}"
android:textSize="12sp"
android:text="Title"
app:layout_constraintStart_toStartOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_event_reviews"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_marginTop="#dimen/vertical_padding"
android:onClick="#{() -> viewModel.handleClick()}"
android:orientation="horizontal"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="parent" />
I want both the title and the recycler view to do the same click function handleClick when either of them is clicks. The title TextView works but the RecyclerView doesn't handle the clicks. How can I accomplish that?
Note: I don't want to wrap both views in one layout since that will add complexity on the entire layout
handleClick(View view) {
switch(view) {
case R.id.tv_amount_reviews:
//handle textview click;
break;
case R.id.rv_event_reviews:
//handle recycler view click;
}
}
If both views have the same function you can add this to your model
public handleClick() {
}
You can then add a listener in your model, example
private OnClickListener onClickListener = null;
interface OnClickListener{
void onClick();
}
public handleClick() {
if(onClickListener != null) onClickListener.onClick();
}
public void setOnClickListener(OnClickListener onClickListener){
this.onClickListener = onClickListener;
}
If you want to check which view was clicked you would need to change the line below, and then add a view parameter to handleClick(View v)
#{() -> viewModel.handleClick()}
to
#{(v) -> viewModel.handleClick(v)} // Don't forget to add a View argument to handleClick

how to turn off parent recycler view onclick response after child view already responded?

I am using a recyclerview that the viewholder entry has an imageview. Both have an onclick listener. If the child image view responded to the onclick, I don't want the recylerview onClick to respond to it. If the clicked location is not on the imageviewer, I want the recyclerview to respond. My research so far shows that usually this situation can be handled by using the same function to respond to both onClick events, but the problem is that recyclerview onclick and its child imageview onClick are different. I don't see how they can be handled in the same function. Right now I have a hacking workaround to use a global variable to indicate that the imageview has already responded to this click, and put up a 200ms delay on recyclerview listener to check the global variable before responding. Is there a more proper way of doing this?
I just noticed that if I add an "onClick" for every type of child views of the recycler view and remove the listener on the recyclerview, that can work. Right now I only have two child views anyway. Although I will be adding a lot more, it's still manageable. If there's no better way, I'll probably just do that.
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="true"
android:paddingLeft="16dp"
android:paddingRight="4dp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:clickable="true"
android:background="?android:attr/selectableItemBackground"
android:orientation="vertical">
<TextView
android:id="#+id/lstItemName"
android:textColor="#color/title"
android:textSize="16dp"
android:textStyle="bold"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="#+id/lstItemReportby"
android:layout_gravity="left"
android:layout_width="0dp"
android:layout_height="wrap_content"
/>
<ImageView
android:id="#+id/lstItemMap"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginRight="2dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"/>
</android.support.constraint.ConstraintLayout>
public class TrackedItemListAdapter extends RecyclerView.Adapter<TrackedItemListAdapter.MyViewHolder>{
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView m_itemName, m_itemDes, m_itemReportedBy, m_itemHiddenText;
public ImageView m_itemMapDrop;
public MyViewHolder(View view) {
super(view);
m_itemName = (TextView) view.findViewById(R.id.lstItemName);
m_itemMapDrop = (ImageView) view.findViewById(R.id.lstItemMap);
}
}
#Override
public void onBindViewHolder(TrackedItemListAdapter.MyViewHolder holder, int position) {
holder.m_itemName.setText(obj.getName());
holder.m_itemMapDrop.setImageResource(R.drawable.ic_img_nomap);
holder.m_itemMapDrop.setOnClickListener(new View.OnClickListener() {
//#Override
public void onClick(View v) {
startMap();
}
});
}
}
m_trackedItemListAdapter = new TrackedItemListAdapter();
m_recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
m_recyclerView.setHasFixedSize(true);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
m_recyclerView.setLayoutManager(mLayoutManager);
m_recyclerView.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL));
m_recyclerView.setItemAnimator(new DefaultItemAnimator());
m_recyclerView.setAdapter(m_trackedItemListAdapter);
m_recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getApplicationContext(), m_recyclerView, new RecyclerTouchListener.ClickListener() {
#Override
public void onClick(View view, int position) {
//a hack to turn off response if the imageview for location already responded
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
popupItemContent();
}
}, 200);
}
}
use this in your ConstraintLayout:
descendantFocusability="blocksDescendants"

RecyclerView OnClickListener (On entire RV)

My RecyclerView:
<android.support.v7.widget.RecyclerView
android:background="?android:selectableItemBackground"
app:layoutManager="android.support.v7.widget.LinearLayoutManager"
android:id="#+id/crash_course_item_dates"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:clickable="true"
/>
ClickListener:
holder.crashCoursesDateRecyclerView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
crashCourseListener.onCrashCourseClick(crashCourse);
}
});
However it's not working when I click on the recyclerview. I thought it might be that the clicklistener is being triggered by the items inside the recyclerview. So what I tried is setting clickable=false in the recyclerview Items' layout and settings the layout's onClickListener(null) but it't not working.
update
Thanks for all your answers, I should have explained better, i have a recyclerview inside another recyclerview item, each item of the latter has a recyclerview inside. I fixed this problem by putting the recyclerview in a frame layout and adding another layout 'on top' of the recyclervjew and setting the onClickListener on that layout.
As Recycler view doesnot support on itemClick Listener ,Implement a simplelistener interface and call that interface in the bindview and pass it to the main class.Please find the piece of code below for
public interface OnItemClickListener {
public void onItemClick(View view, int position);
}
Adapter Constructor
public ContentAdapter(List<ContentItem> items, OnItemClickListener listener) {
this.items = items;
this.listener = listener;
}
in Bind View Holder
holder.setOnClickListener(new View.OnClickListener() {
#Override public void onClick(View v) {
listener.onItemClick(item);
}
});
Implement your activity with the OnItemClickListener and in the callbacks add your required code.
You just simple call in your onBindViewHolder() method at where you have may be your own holder class.
So use holder.itemView.setOnClickListener(new setOn....){
At where itemView is the view which is inflated in onCreateViewHolder method.
As per my understanding you want click of complete Recycler view,
Try this,
RecyclerView rv = (RecyclerView) findViewById(R.id.recycler_view);
rv.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//your action
}
});
first of all your question is not clear to me but still what i have understood u want you perform click listener on the each item of the try this
in your recyclerview's item layout
<LinearLayout
android:id="#+id/linearlayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
><TextView
android:id="#+id/linearlayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Demo"
android:clickable="false"
/>
</LinearLayout>
Now in item ItemHolder class
public class Demo extends ItemHolder {
LinearLayout ll;
public Demo(View view) {
ll=(LinearLayout)view.findViewById(R.id.linearlayout);
ll.setOnClickListener(View View){
}

Android onTouchListener not working, works only at the Padding area

I'm definitely doing something wrong. I have a ReclyclerView and the each cell has a XML home_cells.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:paddingRight="12dp"
android:paddingLeft="12dp"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:clickable="true">
<android.support.v7.widget.CardView
android:id="#+id/home_cv"
android:clickable="true"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
......
android:paddingTop="16dp">
<LinearLayout
....
android:orientation="horizontal">
<ImageView
...
android:src="#drawable/abc_ratingbar_full_material" />
<LinearLayout
......
android:orientation="vertical">
<TextView
.....
android:textStyle="bold" />
<TextView
....
android:textColor="#color/secondaryTextColor" />
</LinearLayout>
<ImageView
....
android:src="#mipmap/ic_chevron_right_black_24dp" />
</LinearLayout>
</RelativeLayout>
</android.support.v7.widget.CardView>
<!--<lay-->
</LinearLayout>
I have an adapter... everything works fine..... no problem at all.
BUT, when i try to implement onClickLister to complete cell view mView IT DOES NOT WORK. If I touch in the corner ( where i have padding) IT WORKS.
I have no idea what is happening. If i set listener to every element in the cell it works... but not the whole cell.
Below is my viewHolder
class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
CardView cv;
ImageView icon;
TextView heading;
TextView subheading;
View mView;
public MyViewHolder(View itemView) {
super(itemView);
Log.d(TAG, "setting images and items");
mView=itemView;
cv = (CardView)itemView.findViewById(R.id.home_cv);
icon =(ImageView) itemView.findViewById(R.id.home_rv_icon);
heading =(TextView) itemView.findViewById(R.id.heading);
subheading =(TextView) itemView.findViewById(R.id.subhead);
icon.setOnClickListener(this); // Working
mView.setOnClickListener(this); // NOT working
mView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View arg0, MotionEvent arg1) {
// NOT Working
return true;
}
});
}
#Override
public void onClick(View view) {
//
Log.d(TAG,"on click");
if(clickListener!=null){
Log.d(TAG,"listner notnull");
clickListener.itemClick(view,getAdapterPosition());
}
}
}
public interface RVClickListener{
//OnClick will work, but for better coding standard i made this listener to call the onclick from the fragment it self..
public void itemClick(View view, int position );
}
After few hours of struggle if finally fixed it. Here is the problem.
Since my layout has child views (layouts) the onclicklistener is being captured by them.
So solved it by a simple solution. I turned off the clickable for all the child views and applied the click listener to the parent.
To all the child views:
android:clickable="false"
Remove longClickable = "true" from every child view of the CardView Layout

How to make a TextView Clickable with a extra ID in android

I am developing a Android Application, where i have multiple textView and I want those textview clickable. When I will click those textView I will get a common empty form but with a static ID in the top for every textview.
For example: If I have 3 product name in 3 text view, if I click on textView1, a previously made layout will be shown and there will be a static ID with my product name in the top, then there will be form to filling up the details of the product.If I click on the textView2 then the form will be same only the Static ID and the product name will change.
I hope you guys understood what I wanted to explain.
I am new in application development so I need some simple solution.
So far I have made a layout of my form and I have also made a clickable Layout. So I need to know how I would make the class and function to call the layout and plus the static ID.
Layout of the product name and the Clickable TextView:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/p85"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="11dp"
android:textStyle="bold"
android:layout_marginTop="12dp"
android:text="#string/p85"
android:ems="7"
android:textSize="35sp"
android:textColor="#375C34"
android:clickable="true"
android:background="#drawable/product_list_view"
android:textAppearance="?android:attr/textAppearanceLarge" />
</LinearLayout>
</ScrollView>
ProductList.java file that call the product_list.xml
import android.app.Activity;
import android.os.Bundle;
public class ProductList extends Activity {
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.product_list);
}
}
In xml in your textview put :
android:onClick="onClick"
And have this
public void onClick(View v) {
switch(v.getId()){
case R.id.TextViewFromXml):
// do something
break;
}
}
Or Remove this
Textview.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
}
});
First set Tag(i.e your Static ID) to TextView and then set Clicklistner
tv.setTag("1234");
tv.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
myId=tv.getTag();
}
});

Categories

Resources