Button onClick Doesn't Work Inside Tab Layout - android

I have a TabLayout, and it have 3 tab items inside it (Accepted, Rejected, and Pending). Each of them have a recyclerlist for different status (Use 1 Adapter for it). In Tab Pending I have a button to delete the item, but the button doesnt respond to any click input. I already set the clickListener in the adapter and fragment but it still doesn't work.
I may miss something in the process, so I really need any help. Thank You.
This is the xml for list inside recycle view
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/tools">
<data>
<variable
name="overrideHistory"
type="example.com.absensiapp.model.OverrideHistoryRespModel" />
<variable
name="onClick"
type="example.com.absensiapp.view.listener.OverrideHistoryListener" />
</data>
<androidx.appcompat.widget.AppCompatImageButton
android:id="#+id/btn_delete"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="330dp"
android:layout_marginTop="10dp"
android:src="#drawable/ic_delete"
android:backgroundTint="#color/red"
android:tint="#color/white"
android:background="#drawable/circle_button"
card_view:layout_constraintEnd_toEndOf="parent"
card_view:layout_constraintTop_toTopOf="parent"
android:onClick="#{()->onClick.onClickDeleteButton(overrideHistory.id)}"/>
</androidx.cardview.widget.CardView>
This is how i set the listener interface in adapter
public void setOnClick(OverrideHistoryListener listener) {
this.overrideHistoryListener = listener;
}
This is how I set the listener in Fragment for the pending tab
public class HistoryPendingFragment extends Fragment implements OverrideHistoryListener {
overrideHistoryListBinding.setOnClick(this);
}
For the action onClick
public void onClickDeleteButton(String overrideId) {
overrideViewModel.deletePendingOverride(overrideId);
}
This is the interface for listener
public interface OverrideHistoryListener {
void onClickDeleteButton(String overrideId);
}

android:onClick="#{overrideHistory::onClickDeleteButton}"
public void onClickDeleteButton(view: View) {
overrideViewModel.deletePendingOverride(overrideId);
}

Found the answer, I forgot to initialize the Listener in the onBindViewHolder so it looks like this
public void onBindViewHolder(#NonNull OverrideHistoryAdapter.ViewHolder holder, int position) {
holder.overrideHistoryListBinding.setOnClick(this);
}

Related

How to store changed values for RecyclerView adapter

Hi I've started learning android recently and am Trying to get familiar with RecyclerView.
I have a Main menu which is a simple list. When clicked on any item a new activity named subMenu starts. This SubMenu contains a RecyclerView where each item is a cardview having two buttons, that can be used to increase or decrease items quantity (which is also being shown card view). Now I want to retain changes made in Recyclerview for each main menu. Currently I have adapter for only one sub menu.
Any help or sample is appreciated.
Main menu xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainMenu">
<ListView
android:id="#+id/categories_list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/toolbar">
</ListView>
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
Main menu .java file
public class MainMenu extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_menu);
TextView textView=findViewById(R.id.editText);
Toolbar toolbar=findViewById(R.id.toolbar);
toolbar.setTitle("Table "+getIntent().getStringExtra("table_no"));
setSupportActionBar(toolbar);
final ListView listView=findViewById(R.id.categories_list);
ArrayAdapter<String> adapter= new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,getResources().getStringArray(R.array.main_categories));
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent intent=new Intent(MainMenu.this,subMenu.class);
intent.putExtra("main_category",listView.getItemAtPosition(position).toString());
startActivity(intent);
}
});
}
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.custom_menu,menu);
return true;
}
}
sub menu .xml file
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".subMenu">
<Toolbar
android:id="#+id/toolbar2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorPrimary">
</Toolbar>
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerview_submenu"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/toolbar2">
</android.support.v7.widget.RecyclerView>
</android.support.constraint.ConstraintLayout>
Edit
To make my question more clear
Here is main menu
When clicked sub menu opens
The number on top right is quantity that can be incremented or decremented by user as shown below
Now when user moves to main menu and comes back to sub menu of same category these changes in quantity are not retained.
I hope I made myself clear. Simple example would be helpful.
Edit
Adapter code for sub menu RecyclerView.
public class RecyclerViewAdapterSubItems extends RecyclerView.Adapter<RecyclerViewAdapterSubItems.subItemViewHolder> {
private Context context;
private List<SubItems> subItemsList;
public RecyclerViewAdapterSubItems(Context context, List<SubItems> subItemsList){
this.context=context;
this.subItemsList=subItemsList;
}
#Override
public subItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view;
LayoutInflater inflater=LayoutInflater.from(context);
view=inflater.inflate(R.layout.cardview_sub_menu_item,parent,false);
return new subItemViewHolder(view);
}
#Override
public void onBindViewHolder(final subItemViewHolder holder, final int position) {
holder.subItemName.setText(subItemsList.get(position).getName());
holder.subItemPrice.setText(Integer.toString(subItemsList.get(position).getPrice()));
holder.subItemQuantity.setText(Integer.toString(subItemsList.get(position).getQuantity()));
holder.incrementQuantityButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
subItemsList.get(position).setQuantity(subItemsList.get(position).getQuantity()+1);
holder.subItemQuantity.setText(Integer.toString(subItemsList.get(position).getQuantity()));
}
});
}
#Override
public int getItemCount() {
return subItemsList.size();
}
public static class subItemViewHolder extends RecyclerView.ViewHolder {
TextView subItemName;
TextView subItemPrice;
TextView subItemQuantity;
ImageButton incrementQuantityButton;
ImageButton decrementQuantityButton;
public subItemViewHolder(View itemView) {
super(itemView);
subItemName=itemView.findViewById(R.id.textView_sub_item_name);
subItemPrice=itemView.findViewById(R.id.textView_sub__item_price);
subItemQuantity=itemView.findViewById(R.id.textView_sub_item_quantity);
incrementQuantityButton=itemView.findViewById(R.id.imageButton_increment_quantity);
decrementQuantityButton=itemView.findViewById(R.id.imageButton_decrement_quantity);
}
}
}
submenu.java
public class subMenu extends AppCompatActivity {
static List<SubItems> subItemList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sub_menu);
RecyclerView recyclerView=findViewById(R.id.recyclerview_submenu);
subItemList=new ArrayList<>();
subItemList.add(new SubItems("Pasta",20,0));
subItemList.add(new SubItems("Peparoney",20,0));
subItemList.add(new SubItems("asta",40,0));
RecyclerViewAdapterSubItems adapterSubItems=new RecyclerViewAdapterSubItems(this,subItemList);
recyclerView.setAdapter(adapterSubItems);
recyclerView.setLayoutManager(new GridLayoutManager(this,1));
}
}
Your issue is here:
RecyclerView recyclerView=findViewById(R.id.recyclerview_submenu);
subItemList=new ArrayList<>();
subItemList.add(new SubItems("Pasta",20,0));
subItemList.add(new SubItems("Peparoney",20,0));
subItemList.add(new SubItems("asta",40,0));
You are creating new SubItems everytime you start your SubMenuActivity. You need to save these subItems permanently for every category.
One of the way is to create a Category POJO having List<SubItems> and initialize them at the MainMenu Activity and pass that Category POJO on itemClick.
Take an array of Boolean type with size equal to the size of your main menu items.
Initialise all values to false.
And whenever you select any main menu, if it opens, set that position in your array as true and if it closes, set the place as false.
On bindViewHolder add a condition like if the array value is true, show the sub menu else hide the sub menu
And you can also store this array in database to retain the value if you need it even after you kill your application.
Let me know if you need help with the code.

Binding event not firing on Adapter

I am following Android Archt. component to build a project. Following the guidelines I have created a custom Adapter named CataloguesAdapter extending DataBoundListAdapter as :
public class CataloguesAdapter extends DataBoundListAdapter<CatalogueEntity, CatalogueItemBinding> {
private final android.databinding.DataBindingComponent dataBindingComponent;
private final ContributorClickCallback callback;
private CatalogueItemBinding mBinding;
public CataloguesAdapter(DataBindingComponent dataBindingComponent,
ContributorClickCallback callback) {
this.dataBindingComponent = dataBindingComponent;
this.callback = callback;
}
#Override
protected CatalogueItemBinding createBinding(ViewGroup parent) {
mBinding = DataBindingUtil
.inflate(LayoutInflater.from(parent.getContext()),
R.layout.catalogue_item, parent, false,
dataBindingComponent);
//while this click event is working fine
mBinding.getRoot().setOnClickListener(v -> {
CatalogueEntity catalogueEntity = mBinding.getCatalogue();
if (catalogueEntity != null && callback != null) {
callback.onClick(catalogueEntity);
}
});
//todo:not working, this event is not firing
mBinding.deleteIcon.setOnClickListener(v-> callback.onItemDelete());
return mBinding;
}
}
I am implementing swipe to delete layout on Recycler view item. Below is the XML layout of list item:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="catalogue"
type="com.mindtree.igxbridge.traderapp.datasource.local.entity.CatalogueEntity" />
</data>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardUseCompatPadding="true">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:id="#+id/view_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/colorRed">
<ImageView
android:id="#+id/delete_icon"
android:layout_width="#dimen/dimen_30_dp"
android:layout_height="#dimen/dimen_30_dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="#dimen/dimen_10_dp"
app:srcCompat="#drawable/ic_delete"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginEnd="#dimen/dimen_10_dp"
android:layout_toStartOf="#id/delete_icon"
android:text="#string/text_delete"
android:textColor="#color/Material.87.white"
android:textSize="14sp" />
</RelativeLayout>
<RelativeLayout
android:id="#+id/view_foreground"
android:layout_width="match_parent"
android:background="#FFFFFF"
android:layout_height="wrap_content">
<android.support.v7.widget.AppCompatImageView
android:id="#+id/arrow_icon"
android:layout_width="#dimen/dimen_30_dp"
android:layout_height="#dimen/dimen_30_dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="#dimen/dimen_10_dp"
app:srcCompat="#drawable/ic_arrow_right" />
</RelativeLayout>
</FrameLayout>
</android.support.v7.widget.CardView>
</layout>
Another operation like swipe left/right is working fine but clicking on Delete button event is not getting called.
I tried checking findViewbyId and register click event by that, but no luck with that too.
While CatalogueItemBinding is registered correctly, I am not able to find any other source of error.
Thanks.
Correct me if I have misunderstood your code. You used a FrameLayout to host two relative layouts one top of each other (foreground and background). The delete button is in the background and foreground has match_parent in its width attribute. Therefore, I think the delete button is getting covered by the foreground, leading to "not firing of the event".
Possible Solution
Try incorporating the delete button in the foreground. It makes sense to put UI components in the front.
I think you forget to tell your adapter class to where your XML is set or not to adapter class. just create a variable in XML which will import your adapter class have look.
<variable
name="myAdapter"
type="import your adapter class">
</variable>
Now set this variable to your adapter.
#Override
protected CatalogueItemBinding createBinding(ViewGroup parent) {
mBinding = DataBindingUtil
.inflate(LayoutInflater.from(parent.getContext()),
R.layout.catalogue_item, parent, false,
dataBindingComponent);
mBinding .setmyAdapter(this);
return mBinding;
}
}
then your click will work. Hope it will help you.

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){
}

Respond to buttons click in RecyclerView

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
}
});
}
}

Categories

Resources