How to do something with focused item of RecyclerView? - android

I have a simple RecyclerView with only a TextView as each item. By using recyclerView.smoothScrollToPosition(myPosition); in MainActivity, I can scroll to custom item. What I need is changing textColor for current item that is scrolled to, just after scrolling.
For example, if myPosition is 3 and 3rd item of RecyclerView is "current" or "focused", I want to change textColor for this 3rd item.
How can I do that?
MainActivity.java:
public class MainActivity extends AppCompatActivity implements MyAdapter.ItemClickListener {
MyAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ArrayList<String> itemTitle_List = new ArrayList<>();
itemTitle_List.add("facebook");
itemTitle_List.add("flickr");
itemTitle_List.add("google_plus");
itemTitle_List.add("instagram");
itemTitle_List.add("linkedin");
itemTitle_List.add("pinterest");
itemTitle_List.add("soundcloud");
itemTitle_List.add("swarm");
itemTitle_List.add("tumblr");
itemTitle_List.add("twitter");
// set up the RecyclerView
RecyclerView recyclerView = findViewById(R.id.recycler_view);
RecyclerView.LayoutManager layoutManager=new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
adapter = new MyAdapter(this, itemTitle_List);
adapter.setClickListener(this);
recyclerView.setAdapter(adapter);
recyclerView.smoothScrollToPosition(3);
}
#Override
public void onItemClick(View view, int position) {
//Toast.makeText(this, "You clicked " + adapter.getItem(position) + " on row number " + position, Toast.LENGTH_SHORT).show();
}
}
MyAdapter.java:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private List<String> itemTitle_List;
private LayoutInflater layoutInflater;
private ItemClickListener itemClickListener;
// data is passed into the constructor
MyAdapter(Context context, List<String> itemTitle_List) {
this.layoutInflater = LayoutInflater.from(context);
this.itemTitle_List = itemTitle_List;
}
// inflates the row layout from xml when needed
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = layoutInflater.inflate(R.layout.recyclerview_row, parent, false);
return new ViewHolder(view);
}
// total number of rows
#Override
public int getItemCount() {
return itemTitle_List.size();
}
// binds the title to the TextView, and image to the ImageView in each row
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
String title = itemTitle_List.get(position);
holder.textView.setText(title);
}
// stores and recycles views as they are scrolled off screen
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView textView;
ViewHolder(View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.text_view);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
if (itemClickListener != null) itemClickListener.onItemClick(view, getAdapterPosition());
}
}
// convenience method for getting data at click position
String getItem(int id) {
return itemTitle_List.get(id);
}
// allows clicks events to be caught
void setClickListener(ItemClickListener itemClickListener) {
this.itemClickListener = itemClickListener;
}
// parent activity will implement this method to respond to click events
public interface ItemClickListener {
void onItemClick(View view, int position);
}
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/recycler_view">
</android.support.v7.widget.RecyclerView>
</RelativeLayout>
recyclerview_row.xml:
<?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="80dp"
android:orientation="horizontal"
android:padding="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/text_view"
android:layout_gravity="center_vertical"
android:layout_margin="10dp"/>
</LinearLayout>

I found a simple solution, but I'm not sure if this is standard or not.
Add a public integer, named row_index=0 and a public function, in MyAdapter.java, as below:
public void selectRow(int index){
row_index=index;
notifyDataSetChanged();
}
And in the onBindViewHolder function in MyAdapter.java, add this code:
if(position==row_index){
holder.textView.setTextColor(Color.RED);
}
else{
holder.textView.setTextColor(Color.BLACK);
}
Then, after recyclerView.smoothScrollToPosition(3) in MainActivity.java, use this:
MyAdapter.selectRow(3);
MyAdapter.notifyDataSetChanged();
This way, when RecyclerView scrolled to 3rd item, the textColor for this item changes to Red.

Related

OnClickListener for headers of RecyclerView is not getting invoked

I want to sort my recyclerview on click of a column header (e.g if Name and age are two columns of the recyclerview, I want to sort the list when I click on header Age). I have added the headers by including the headers layout in my activity layout that contains recyclerview.
<RelativeLayout
android:id="#+id/activity_main"
android:layout_width="wrap_content"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<include layout="#layout/header_item"/>
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/swipeContainer"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:divider="#null"
android:paddingBottom="#dimen/intrinsic_padding"
android:paddingTop="50dp"/>
</android.support.v4.widget.SwipeRefreshLayout>
</RelativeLayout>
In my activity class with above layout, I set the adapter for recyclerview and add onClickListener for Textview Age.
public class MainActivity extends AppCompatActivity {
TextView ageTextview;
private RecyclerView mRecyclerView;
private RecyclerView.Adapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ArrayList<User> usersList=initUsers();
// Create RecyclerView List
mRecyclerView=findViewById(R.id.my_recycler_view);
mRecyclerView.setHasFixedSize(true);
mLayoutManager=new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
mAdapter=new RecyclerAdapter(usersList, getApplicationContext());
mRecyclerView.setAdapter(mAdapter);
ageTextview=findViewById(R.id.ageHeader);
ageTextview.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(context, "Column -- Name", Toast.LENGTH_SHORT).show();
Collections.sort(usersList, new Comparator<User>() {
#Override
public int compare(User user1, User user2) {
if (user1.getAge() < user2.getAge())
return -1;
else if (user1.getAge()==user2.getAge())
return 0;
else
return 1;
}
});
mAdapter.notifyDataSetChanged();
}
});
}
}
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private ArrayList<User> users;
private Context context;
RecyclerAdapter(ArrayList<User> users, Context context)
{
this.users=users;
this.context=context;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view=LayoutInflater.from(parent.getContext()).inflate(R.layout.item_user, parent, false);
return new VHItem(view);
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof VHItem) {
User user = users.get(position);
((VHItem)holder).userName.setText(user.getUserName());
((VHItem)holder).age.setText(String.valueOf(user.getAge()));
}
}
#Override
public int getItemCount() {
if (users !=null)
{
System.out.println("Number of users: "+ users.size());
return users.size();
}
else {
return 0;
}
}
public static class VHItem extends RecyclerView.ViewHolder {
public View view;
TextView userName;
TextView age;
VHItem(View view)
{
super(view);
this.view=view;
this.userName=view.findViewById(R.id.username);
this.age=view.findViewById(R.id.age);
}
}
}
When I click on Age header, there is no effect. Neither sorting happens nor Toast is displayed. Looks like onClick() method is not getting invoked at all. The log does not show any errors.
In the layout file header_item, I have tried adding android:clickable="true", android:focusable="false". But nothing works.
Please help me understand if I am doing anything wrong. Is adding headers using a separate layout file the problem?
Thanks
Try to get OnClickListner from ViewHolder. Like this,
class ViewHolder extends RecyclerView.ViewHolder{
public TextView ageTextview;
public ViewHolder(View itemView) {
super(itemView);
ageTextview = temView.findViewById(R.id.ageTextview) ;
ageTextview.setOnClickListener(..);
}
}

RecyclerView Databinding Item click

I am trying to listen for row clicks (item clicks) on my recycler view from the Activity itself (not from adapter).
My Adapter so far looks like this:
public class ListMiestnostiAdapter extends RecyclerView.Adapter<ListMiestnostiAdapter.ViewHolder>{
private List<Miestnost> data;
// you provide access to all the views for a data item in a view holder
public static class ViewHolder extends RecyclerView.ViewHolder {
public ViewDataBinding binding;
public ViewHolder(ViewDataBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
public void bind(Object obj){
binding.setVariable(BR.obj, obj);
binding.executePendingBindings();
}
}
public ListMiestnostiAdapter(List<Miestnost> data) {
this.data = data;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// create a new view
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
ActivityListMiestnostiRowBinding itemBinding = ActivityListMiestnostiRowBinding.inflate(inflater, parent,false);
return new ViewHolder(itemBinding);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
Miestnost item = data.get(position);
holder.bind(item);
}
#Override
public int getItemCount() {
return data.size();
}
}
And my row layout like this:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="obj"
type="com.example.com.projectname.Models.Miestnost" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:orientation="horizontal"
android:paddingBottom="#dimen/row_padding_vertical"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/row_padding_vertical">
<TextView
android:id="#+id/txt_miestnost_row_nazov"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:text="#{obj.Name}"
android:textSize="16dp" />
</LinearLayout>
</layout>
As I have already mentioned I am trying to listen to item clicks, but not from Adapter itself (as other posts suggested), but from my Activity which holds this RecyclerView.
Is such action even possible? If yes, then any help would be highly appreciated as I could not find anything on google.
You’ll first need an interface that specifies listener’s behavior. In this example, there is a sample model called ContentItem, so the click will return an item of that type:
public interface OnItemClickListener {
void onItemClick(ContentItem item);
}
The constructor will receive an object that implements this interface, along with the items to be rendered:
private final List<ContentItem> items;
private final OnItemClickListener listener;
public ContentAdapter(List<ContentItem> items, OnItemClickListener listener) {
this.items = items;
this.listener = listener;
}
You could alternatively create a setOnItemClickListener method and assign it that way. Now, in onBindViewHolder the ViewHolder will receive the constructor in the custom bind method:
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.bind(items.get(position), listener);
}
This is how this bind method looks:
public void bind(final ContentItem item, final OnItemClickListener listener) {
...
itemView.setOnClickListener(new View.OnClickListener() {
#Override public void onClick(View v) {
listener.onItemClick(item);
}
});
}
Use it whenever you need it by creating a new adapter and the listener that will implement the behavior when an item is clicked. A simple example:
recycler.setAdapter(new ContentAdapter(
items,
new ContentAdapter.OnItemClickListener() {
#Override
public void onItemClick(ContentItem item) {
Toast.makeText(getContext(), "Item Clicked", Toast.LENGTH_LONG).show();
}
}));
Source
To add to the answer provided by João Alvares Neto, we can call the OnItemClickListener directly from the layout.
In the variable tag, we can pass the OnItemClickListener and call it using the android:onClick property.
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="storyClickListener"
type="com.hoomanwe.zorro.ui.adapter.OnStoryClickListener" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="#{() -> storyClickListener.onStoryClick(item.id)}" />
</layout>
By this way, you can eliminate the following code from the solution provided by João Alvares Neto
public void bind(final ContentItem item, final OnItemClickListener listener) {
itemView.setOnClickListener(new View.OnClickListener() {
#Override public void onClick(View v) {
listener.onItemClick(item);
}
});
}

listView items with group

I have an ListView with BaseAdapter now I just make some listener to item when I click on item I show some hidden view in item.
Every time I click on some item, I show the hidden view or hide them if views are visible. But the problem I face is that I want to hide the other visible item when the I show a new item.
Here I click on some item and its shows the message date and detail:
Now when I click on other items, I want to hide the first one and show the second, like this:
But here in my code when I click on other item its of course will not hide the previous view. How can I do this trick ?
Simply keep a reference to the last view that was clicked, let's call it mLastViewShown;
new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (mLastViewShown != null)
hideDetails();
mLastViewShown = view;
showDetails();
}
};
Now you have a variable to hide the details from the last user click.
So you want to hide all item's additional field when you click on some other item. In addition to this you also want to toggle visibility of an item's additional view on click on same item.
Here is your main activity:
public class MainActivity extends AppCompatActivity {
private List<ListData> list=new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//get the toolbar instance
handleListClick();
list.add(new ListData("George","Surgeon"));
list.add(new ListData("Nancy","Dentist"));
list.add(new ListData("Henry","Nurse"));
}
private void handleListClick() {
ListView listView=findViewById(R.id.listView);
final CustomBaseAdapter customBaseAdapter=new CustomBaseAdapter(this,list);
listView.setAdapter(customBaseAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
customBaseAdapter.setCurrentSelected(position);
customBaseAdapter.notifyDataSetChanged();
}
});
}
}
Here is your custom base adapter:
public class CustomBaseAdapter extends BaseAdapter {
private List<ListData> myList = new ArrayList<ListData>();
private LayoutInflater inflater;
private Context context;
private int previousSelected=-1;
public CustomBaseAdapter(Context context, List<ListData> myList) {
this.myList = myList;
this.context = context;
inflater = LayoutInflater.from(this.context);
}
public void setCurrentSelected(int currentSelected){
if(previousSelected==currentSelected)
previousSelected=-1;
else
previousSelected=currentSelected;
}
#Override
public int getCount() {
return myList.size();
}
#Override
public ListData getItem(int position) {
return myList.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
MyViewHolder mViewHolder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.row_item, parent, false);
mViewHolder = new MyViewHolder(convertView);
convertView.setTag(mViewHolder);
} else {
mViewHolder = (MyViewHolder) convertView.getTag();
}
ListData currentListData = getItem(position);
mViewHolder.tvMain.setText(currentListData.getMainText());
if(previousSelected==position){
mViewHolder.tvAdditional.setVisibility(TextView.VISIBLE);
mViewHolder.tvAdditional.setText(currentListData.getAdditionalText());
}else{
mViewHolder.tvAdditional.setVisibility(TextView.GONE);
}
return convertView;
}
private class MyViewHolder {
TextView tvMain, tvAdditional;
public MyViewHolder(View item) {
tvMain = (TextView) item.findViewById(R.id.main_text);
tvAdditional = (TextView) item.findViewById(R.id.additional_text);
}
}
}
Here is your ListData:
public class ListData {
private String mainText;
private String additionalText;
public ListData(String mainText, String additionalText) {
this.mainText = mainText;
this.additionalText = additionalText;
}
public String getMainText() {
return mainText;
}
public void setMainText(String mainText) {
this.mainText = mainText;
}
public String getAdditionalText() {
return additionalText;
}
public void setAdditionalText(String additionalText) {
this.additionalText = additionalText;
}
}
Here is your row_item.xml layout file:
<?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="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/main_text"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/additional_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
</LinearLayout>
Here is activity_main.xml layout file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.dexter.stackoverflow.MainActivity">
<ListView
android:id="#+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>

How can I set OnClickListener to two buttons in RecyclerView?

In my android app I have one activity to show a RecyclerView in which each row is composed by a TextView and 2 buttons. Just like that:
Well, following many explanations of internet I have made this Adapter:
public class ListAdapter extends
RecyclerView.Adapter<ListAdapter.ViewHolder> {
private LayoutInflater layoutInflater;
protected Vector<List> lists;
public ListAdapter(Context context, Vector lists) {
layoutInflater = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.lists = lists;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = layoutInflater.inflate(R.layout.listadapter, null);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
List list = lists.elementAt(position);
holder.name.setText(list.getName());
//holder.delete.set HOW DO I GET BUTTON HERE?
}
#Override
public int getItemCount() {
return lists.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder
implements View.OnClickListener {
public TextView name;
public Button edit;
public Button delete;
public ViewHolder(View itemView) {
super(itemView);
name = (TextView) itemView.findViewById(R.id.listname);
edit = (Button) itemView.findViewById(R.id.edit);
delete = (Button) itemView.findViewById(R.id.delete);
edit.setOnClickListener(this);
}
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.edit:
break;
case R.id.delete:
break;
default:
break;
}
}
}
}
I haven't found examples of having 2 buttons (there are only examples of adding images) in each view of the recyclerview, as in the first image. I mean, guess I have 10 List elements in my RecyclerView, how can I have in each of them to one side a TextView with the name of the List and 2 buttons and handle clickListener?. As in the following image, which I have done by hand for you to see what I am talking about:
This is the activity that will show the recyclerView; don't take it into account because I am pretty sure the way is wrong. I get lists information from sqlite database:
public class ShowListOfLists extends AppCompatActivity {
private RecyclerView recyclerView;
private RecyclerView.LayoutManager layoutManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_show_list_of_lists);
LocalDB localDB = new LocalDB(this, "localBD", null, 1);
Vector <List> ListAdapter = localDB.getAllPrivateList();
recyclerView = (RecyclerView) findViewById(R.id.recyclerviewlistas);
recyclerView.setAdapter(new ListAdapter(this, ListAdapter));
layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
}
A list have the following attributes:
-idList int
-name String
-Description String
-creationDate Date
-active int (0 or 1)
-deactivationDate Date
Thank you in advance.
/*******************************EDIT****************************************/
Thank to you I have been able to show the recyclerView and it works well. But I see that:
Instead of that:
This the XML code and design of the adapter:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="#drawable/rectangle_bg"
android:orientation="horizontal"
android:weightSum="1"
android:layout_marginTop="5dp">
<TextView
android:id="#+id/listname"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_weight="0.75"
android:gravity="center_vertical"
android:text="TextView"
android:textSize="15sp"/>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.25"
android:gravity="end"
android:orientation="vertical">
<ImageButton
android:id="#+id/delete"
android:layout_width="match_parent"
android:layout_height="30dp"
android:background="#android:color/transparent"
android:contentDescription="Delete"
app:srcCompat="#android:drawable/ic_menu_delete" />
<ImageButton
android:id="#+id/edit"
android:layout_width="match_parent"
android:layout_height="30dp"
android:background="#android:color/transparent"
android:contentDescription="Edit"
app:srcCompat="#android:drawable/ic_menu_edit" />
</LinearLayout>
</LinearLayout>
And this is the XML of the recyclerview
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView
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="wrap_content"
android:layout_height="match_parent"
tools:context="com.pc.kanayel.runoutof.ShowListOfLists"
android:orientation="vertical"
android:id="#+id/recyclerviewlistas">
</android.support.v7.widget.RecyclerView>
You just need to add some code to your ListAdapter. It is there, where you have to implement onClickListener. The code for your case should look something like the one below.
You can pass any parameter you need to. It depends on the functionality you want to achieve. Here I have demonstrated passing the order of item clicked inside of list.
Option 1 (power/performance efficient)
So, what does the code below actually mean? You have already created a ViewHolder and implemented OnClickListener. That is correct. Now you need to set OnClickListener to two buttons. But what these buttons will do when clicked is defined by the interface we created inside of ViewHolder.
When app will run RecyclerView will create as many ViewHolders as it is needs to fill the available screen with list items by calling onCreateViewHolder() method for each of viewholders. When you scroll up/down these ViewHolders will be reused. OnCreateViewHolder() is not called, only onBindViewHolder() is called to update the content of viewholder. The code below made so that, when ViewHolder is created it will also create an MyClickListener that will be used by OnClickListener of viewholder and when viewholder is reused it will not create new OnClickListener. It means that our method is performance efficient.
Option 2 (not efficient)
You could also setOnClickListener() inside of onBindViewHolder(). However, as I have mentioned in the paragraph above, this method is called every time you scroll to update the content of viewholder. Now it would create new OnClickListener object everytime. While Option 1 has OnClickListener on every ViewHolder and it reuses them.
Code for Option 1
public class ListAdapter extends RecyclerView.Adapter<ListAdapter.ViewHolder> {
private LayoutInflater layoutInflater;
protected Vector<List> lists;
public ListAdapter(Context context, Vector lists) {
layoutInflater = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.lists = lists;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = layoutInflater.inflate(R.layout.listadapter, null);
ViewHolder holder = new ViewHolder(view, new MyClickListener() {
#Override
public void onEdit(int p) {
// Implement your functionality for onEdit here
}
#Override
public void onDelete(int p) {
// Implement your functionality for onDelete here
}
});
return holder;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
List list = lists.elementAt(position);
holder.name.setText(list.getName());
}
#Override
public int getItemCount() {
return lists.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
MyClickListener listener;
TextView name;
Button edit;
Button delete;
public ViewHolder(View itemView, MyClickListener listener) {
super(itemView);
name = (TextView) itemView.findViewById(R.id.listname);
edit = (Button) itemView.findViewById(R.id.edit);
delete = (Button) itemView.findViewById(R.id.delete);
this.listener = listener;
edit.setOnClickListener(this);
delete.setOnClickListener(this);
}
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.edit:
listener.onEdit(this.getLayoutPosition());
break;
case R.id.delete:
listener.onDelete(this.getLayoutPosition());
break;
default:
break;
}
}
}
public interface MyClickListener {
void onEdit(int p);
void onDelete(int p);
}
}
Edit for your second question
To make list items take all the width set the width of your recyclerview to match_parent. It is also better to make it a child view of some layout. For instance as given below.
<RelativeLayout
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="com.pc.kanayel.runoutof.ShowListOfLists">
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerviewlistas"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<RelativeLayout>
And change this code inside of your adapter:
View view = layoutInflater.inflate(R.layout.listadapter, null);
to this:
View view = layoutInflater.inflate(R.layout.listadapter, parent, false);
You can do simply like this:
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
List list = lists.elementAt(position);
holder.name.setText(list.getName());
holder.edit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Do your stuff
}
});
holder.delete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Do your stuff
}
});
}

ReclyclerView and CardView, onclick method perform the action on several CardViews at same time

I've got a RecyclerView which populates from an ArrayList. The output is a CardView layout.
In the Cardview, there are 2 buttons amongst other Views.
They only have to read the current value of a TextView, which by default is 1, and increase or decrease it.
The Arraylist contains 8 items.
When I run the app the UI works fine. Trouble is when I try to modify the value of the TextView.
The value is correctly increased and decreased on the CardView I'm working on, but ALSO the value is modified on another CardView. And in that second CardView, modifying its TextView value, also modifies the first one.
So, what am I doing wrong?
This is my Fragment:
public class Fragment_rosas extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater,ViewGroup container,Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.layout_rosas,container,false);
RecyclerView recyclerview_rosas;
RecyclerView.Adapter adaptador_rv_rosas;
RecyclerView.LayoutManager lm_rosas;
List rosas = new ArrayList();
rosas.add(new Tropa(1,R.drawable.minibarbaro, getResources().getString(R.string.barbaro),7,1));
recyclerview_rosas = (RecyclerView) view.findViewById(R.id.recyclerView_tropasRosas);
recyclerview_rosas.setHasFixedSize(true);
lm_rosas = new LinearLayoutManager(getContext());
recyclerview_rosas.setLayoutManager(lm_rosas);
adaptador_rv_rosas = new AdaptadorTropa(rosas);
recyclerview_rosas.setAdapter(adaptador_rv_rosas);
return view;
}
}
And here the part of code on my Adapter:
#Override
public void onBindViewHolder(final TropaViewHolder viewHolder, int i) {
viewHolder.imagen.setImageResource(items.get(i).getImagen());
viewHolder.nombre.setText(items.get(i).getNombre());
viewHolder.maxnivel.setText(String.valueOf(items.get(i).getNivelMax()));
viewHolder.espacioencamp.setText((String.valueOf(items.get(i).getEspacioEnCamp())));
final String nombre = items.get(i).getNombre();
final int maxnivel = items.get(i).getNivelMax();
viewHolder.nivelmas.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String niveltemp = viewHolder.nivel.getText().toString();
String nivelmaxtemp = viewHolder.maxnivel.getText().toString();
int nivel = Integer.parseInt(niveltemp);
int maxxnivel = Integer.parseInt(nivelmaxtemp);
int nuevonivel = nivel+1 ;
if (nuevonivel<=maxxnivel) {
viewHolder.txtv_nivel.setText(String.valueOf(nuevonivel));
}
}
});
My OnCreateViewHolder (nothing really happens here):
#Override
public TropaViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.cardview, viewGroup, false);
return new TropaViewHolder(v);
}
Here is the solution, as mentioned in the comment above, it addresses two problems:
1. positiontoValueMap - saves current value for each position
2. onclicklistener is passed to the ViewHolder in onCreateViewHolder
Adapter Class
public class MyAdapter extends RecyclerView.Adapter {
private Context context;
private List<String> dataList;
private Map<Integer, Integer> positionToValueMap = new HashMap<>();
public MyAdapter(Context context, List<String> dataList) {
this.context = context;
this.dataList = dataList;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.recycler_view_item, null, false);
return new MyViewHolder(view, new OnRecyclerItemClickListener());
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
((MyViewHolder) holder).onRecyclerItemClickListener.updatePosition(position);
((MyViewHolder) holder).position.setText("" + position);
((MyViewHolder) holder).title.setText(dataList.get(position));
int valueToDisplay = 1;
if(positionToValueMap.containsKey(position)) {
valueToDisplay = positionToValueMap.get(position);
} else {
positionToValueMap.put(position, valueToDisplay);
}
((MyViewHolder) holder).valueView.setText("value: " + valueToDisplay);
}
#Override
public int getItemCount() {
return dataList.size();
}
private class MyViewHolder extends RecyclerView.ViewHolder {
private OnRecyclerItemClickListener onRecyclerItemClickListener;
private TextView position;
private TextView title;
private TextView valueView;
public MyViewHolder(View itemView, OnRecyclerItemClickListener onRecyclerItemClickListener) {
super(itemView);
itemView.setOnClickListener(onRecyclerItemClickListener);
this.onRecyclerItemClickListener = onRecyclerItemClickListener;
this.position = (TextView) itemView.findViewById(R.id.position);
this.title = (TextView) itemView.findViewById(R.id.title);
this.valueView = (TextView) itemView.findViewById(R.id.value_view);
}
}
private class OnRecyclerItemClickListener implements View.OnClickListener {
private int position = -1;
public void updatePosition(int position) {
this.position = position;
}
#Override
public void onClick(View v) {
int oldValue = positionToValueMap.get(position); // get current value
oldValue++; // increment
positionToValueMap.put(position, oldValue); // save current value
notifyItemChanged(position); // update clicked view so that it picks up the new saved value from the positionToValueMap in onBindViewHolder
}
}
}
RecyclerView item layout
<TextView
android:id="#+id/position"
android:layout_width="30dp"
android:layout_height="50dp"
android:textColor="#android:color/white"
android:gravity="center"
android:background="#android:color/holo_green_light"
android:layout_alignParentLeft="true"/>
<TextView
android:id="#+id/title"
android:layout_width="50dp"
android:layout_height="50dp"
android:textColor="#android:color/white"
android:gravity="center"
android:background="#android:color/holo_green_dark"
android:layout_toRightOf="#id/position" />
<TextView
android:id="#+id/value_view"
android:layout_width="match_parent"
android:layout_height="50dp"
android:textColor="#android:color/white"
android:gravity="center"
android:background="#android:color/holo_green_light"
android:layout_toRightOf="#id/title"
android:layout_alignParentRight="true"/>
</RelativeLayout>
And Activity to test it out
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
recyclerView.setAdapter(new MyAdapter(getApplicationContext(), getSampleData()));
}
private static List<String> getSampleData() {
List<String> dataList = new ArrayList<>();
dataList.add("zero");
dataList.add("one");
dataList.add("two");
dataList.add("three");
dataList.add("four");
dataList.add("five");
dataList.add("six");
dataList.add("seven");
dataList.add("eight");
dataList.add("nine");
dataList.add("ten");
dataList.add("eleven");
dataList.add("twelve");
dataList.add("thirteen");
dataList.add("fourteen");
dataList.add("fifteen");
dataList.add("sixteen");
dataList.add("seventeen");
dataList.add("eighteen");
dataList.add("nineteen");
dataList.add("twenty");
return dataList;
}
}
activity layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/root_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white"/>
</RelativeLayout>

Categories

Resources