Im attempting to add two different views to the GridviewLayoutManager using a custom adapter.
However, I cant seem to reference the headerview correctly. When the onbindViewHolder is called it is expecting a "ViewHolder" response, however i really want to reference the HeaderView i crated
Because I cant access the correct view, I also cant reference the TextView within the XML layout I am calling.
here is my customer adaptor class:
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.squareup.picasso.Picasso;
import java.util.ArrayList;
public class ElementsAdapter extends RecyclerView.Adapter<ElementsAdapter.ViewHolder> {
private ArrayList<String> mDataset;
private ArrayList<Integer> mDatamap;
public Context context;
private static final int VIEW_HEADER = 0;
private static final int VIEW_NORMAL = 1;
private View headerView;
private int datasetSize;
public class HeaderHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
public TextView headertext;
public HeaderHolder(View v) {
super(v);
headertext = (TextView) v.findViewById(R.id.headertext);
}
}
public class ViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
public TextView txtHeader;
public TextView txtFooter;
public ImageView imgImage;
public ViewHolder(View v) {
super(v);
txtHeader = (TextView) v.findViewById(R.id.firstLine);
txtFooter = (TextView) v.findViewById(R.id.secondLine);
imgImage = (ImageView) v.findViewById(R.id.icon);
}
}
public ElementsAdapter(ArrayList<String> myDataset, ArrayList<Integer> myDatamap) {
mDataset = myDataset;
myDatamap = mDatamap;
}
#Override
public int getItemViewType(int position) {
return isHeader(position) == 1 ? VIEW_HEADER : VIEW_NORMAL;
}
#Override
public int getItemCount() {
return mDataset.size();
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == VIEW_HEADER) {
// create a new view
View sub_view = LayoutInflater.from(parent.getContext()).inflate(R.layout.header, parent, false);
Context context = sub_view.getContext();
// set the view's size, margins, paddings and layout parameters
ViewHolder vh = new ViewHolder(sub_view);
return vh;
// return new HeaderViewHolder(headerView);
} else {
// create a new view
View sub_view = LayoutInflater.from(parent.getContext()).inflate(R.layout.sub_layout, parent, false);
context = sub_view.getContext();
// set the view's size, margins, paddings and layout parameters
ViewHolder vh = new ViewHolder(sub_view);
return vh;
}
}
#Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
if (isHeader(position) == 1) {
// - get element from your dataset at this position
// - replace the contents of the view with that element
final String name = mDataset.get(position);
// holder.txtHeader.setText(mDataset.get(position));
viewHolder.headertext.setText(name);
} else {
// - get element from your dataset at this position
// - replace the contents of the view with that element
final String name = mDataset.get(position);
Picasso.with(context).load("http://www.500kgiveaway.co.uk/"+name).resize(200,200).into(viewHolder.imgImage);
// holder.txtHeader.setText(mDataset.get(position));
viewHolder.txtHeader.setText(name);
viewHolder.txtHeader.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick (View v){
//remove(name);
}
}
);
viewHolder.txtFooter.setText("Footer: "+mDataset.get(position));
}
//ViewHolder holder = (ViewHolder) viewHolder;
//holder.textView.setText("Position " + (position - 1));
}
public int isHeader(int position) {
return mDatamap.get(position) ==1 ? 1:0;}
}
It seems to me that the isHeader() method will always return 0, since you compare a String with a integer. I assume you would like want to check the position of the current item to be 1.
Try this code instead:
public boolean isHeader(int position) {
return position == 1;
}
Then replace
if (isHeader(position) == 1)...
with
if (isHeader(position))...
I hope this helps.
Edit
The above was intended. Sorry.
In the class definition ElementsAdapter.ViewHolder is inserted as the ViewHolder type. This works for the normal
ElementsAdapter.ViewHolder extends RecyclerView.ViewHolder
but not for
ElementsAdapter.HeaderHolder extends RecyclerView.ViewHolder
since it doesn't extend ElementsAdapter.ViewHolder.
You should therfore specify RecyclerView.ViewHolder instead as a generic type to support both of your types.
Related
I'm trying to learn android development and i was learning about the recyclerView. I want to send a string via an interface when a list item is clicked but I dont know how to do that.Can anyone please tell me what to do to achieve this.
This is my java code of the custom recyclerview adapter that I've created.
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder> {
private String[] localDataSet;
private newsOnCkicked k;
/**
* Provide a reference to the type of views that you are using
* (custom ViewHolder).
*/
public static class ViewHolder extends RecyclerView.ViewHolder {
private final TextView textView;
public ViewHolder(View view) {
super(view);
// Define click listener for the ViewHolder's View
textView = (TextView) view.findViewById(R.id.textView2);
}
public TextView getTextView() {
return textView;
}
}
/**
* Initialize the dataset of the Adapter.
*
* #param dataSet String[] containing the data to populate views to be used
* by RecyclerView.
*/
public CustomAdapter(String[] dataSet,newsOnCkicked k) {
localDataSet = dataSet;
this.k=k;
}
// Create new views (invoked by the layout manager)
#Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
// Create a new view, which defines the UI of the list item
View view = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.mylayout, viewGroup, false);
RecyclerView.ViewHolder v=new ViewHolder(view);
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
k.onItemClicked(localDataSet[v.getAdapterPosition()]);
}
});
return new ViewHolder(view);
}
// Replace the contents of a view (invoked by the layout manager)
#Override
public void onBindViewHolder(ViewHolder viewHolder, final int position) {
// Get element from your dataset at this position and replace the
// contents of the view with that element
viewHolder.getTextView().setText(localDataSet[viewHolder.getAdapterPosition()]);
}
// Return the size of your dataset (invoked by the layout manager)
#Override
public int getItemCount() {
return localDataSet.length;
}
}
interface newsOnCkicked extends View.OnClickListener {
String onItemClicked(String s);
}
Kindly help me to figure this out!!
This code seems fine except for these parts i noted you had to do
1)Extending onclick listener
2)The function and position of your interface.
First place your interface in a separate file or inside the adapter class,remove the extends and replace the string to return void:
interface newsOnCkicked {
void onItemClicked(String s);
}
Then call it like this from your activity
new RecyclerView(this)/* <- your recyclerview*/.setAdapter(new CustomAdapter(new String[20]/*your array*/, new CustomAdapter.newsOnCkicked() {
#Override
public void onItemClicked(String s) {
//here s is your clicked string
}
}));
The code should look more or less like below:
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder> {
private String[] localDataSet;
private newsOnCkicked k;
/**
* Provide a reference to the type of views that you are using
* (custom ViewHolder).
*/
public static class ViewHolder extends RecyclerView.ViewHolder {
private final TextView textView;
public ViewHolder(View view) {
super(view);
// Define click listener for the ViewHolder's View
textView = (TextView) view.findViewById(R.id.textView2);
}
public TextView getTextView() {
return textView;
}
}
/**
* Initialize the dataset of the Adapter.
*
* #param dataSet String[] containing the data to populate views to be used
* by RecyclerView.
*/
public CustomAdapter(String[] dataSet,newsOnCkicked k) {
localDataSet = dataSet;
this.k=k;
}
// Create new views (invoked by the layout manager)
#Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
// Create a new view, which defines the UI of the list item
View view = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.mylayout, viewGroup, false);
RecyclerView.ViewHolder v=new ViewHolder(view);
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
k.onItemClicked(localDataSet[v.getAdapterPosition()]);
}
});
return new ViewHolder(view);
}
// Replace the contents of a view (invoked by the layout manager)
#Override
public void onBindViewHolder(ViewHolder viewHolder, final int position) {
// Get element from your dataset at this position and replace the
// contents of the view with that element
viewHolder.getTextView().setText(localDataSet[viewHolder.getAdapterPosition()]);
}
// Return the size of your dataset (invoked by the layout manager)
#Override
public int getItemCount() {
return localDataSet.length;
}
interface newsOnCkicked {
void onItemClicked(String s);
}
}
I have a design for messages.
2 xml files are responsible for the design:
recyclerview_item_incoming.xml
recyclerview_item_outgoing.xml
It looks like this:
Messages are stored inside the RecyclerView.
RecyclerView is connected to SQLite via LiveData -> Room.
More Info
To work with the RecyclerView I have 2 classes:
MessageListAdapter:
package com.mardaunt.telesupp.recyclerview;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.ListAdapter;
import com.mardaunt.telesupp.room.Message;
public class MessageListAdapter extends ListAdapter<Message, MessageViewHolder> {
public static int idMessage = 0; // I added that
public static int countMessages = 0; // I added that
public MessageListAdapter(#NonNull DiffUtil.ItemCallback<Message> diffCallback) {
super(diffCallback);
}
#Override
public MessageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
countMessages = getItemCount();
//System.out.println(countMessages + " - This countMessages\n" + idMessage + "- This idMessage; " + viewType + " - viewType");
System.out.println(idMessage);
//if(idMessage >= countMessages) idMessage = 0;
// I need to pass the create index method of the current message.!!!!!!!!!!
// The getItem() function returns a Message object.
return MessageViewHolder.create(parent, getItem(idMessage));
}
#Override
public void onBindViewHolder(MessageViewHolder holder, int position) {
Message current = getItem(position);
//System.out.println(current.getId() + " " + current.getPhone() + " " + current.getText());
holder.bind(current.getPhone() ,current.getText()); // Бинтим только тело телефон и сообщение!
idMessage = position+1;
if(idMessage >= countMessages) idMessage = 0;
}
public static class MessageDiff extends DiffUtil.ItemCallback<Message> {
#Override
public boolean areItemsTheSame(#NonNull Message oldItem, #NonNull Message newItem) {
return oldItem == newItem;
}
#Override
public boolean areContentsTheSame(#NonNull Message oldItem, #NonNull Message newItem) {
return oldItem.getText().equals(newItem.getText());
}
}
}
MessageViewHolder:
package com.mardaunt.telesupp.recyclerview;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import com.mardaunt.telesupp.R;
import com.mardaunt.telesupp.room.Message;
class MessageViewHolder extends RecyclerView.ViewHolder {
private final TextView phoneItemView;
private final TextView messageItemView;
private MessageViewHolder(View itemView) {
super(itemView);
messageItemView = itemView.findViewById(R.id.text_view_message);
phoneItemView = itemView.findViewById(R.id.text_view_phone);
}
public void bind(String phone, String message) {
phoneItemView.setText(phone);
messageItemView.setText(message);
}
//The method decides which design to choose for the message bubble.
static MessageViewHolder create(ViewGroup parent, Message current) {
View view;
if (current.getNature().equals("outgoing"))
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.recyclerview_item_outgoing, parent, false);
else view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.recyclerview_item_incoming, parent, false);
return new MessageViewHolder(view);
}
}
And Message:
package com.mardaunt.telesupp.room;
import androidx.annotation.NonNull;
import androidx.room.Entity;
import androidx.room.PrimaryKey;
#Entity(tableName = "messages_table")
public class Message {
#PrimaryKey(autoGenerate = true)
private int id;
private String phone;
private String text;
private String nature;
public Message(int id,
#NonNull String phone,
#NonNull String text,
#NonNull String nature
) {
this.id = id;
this.phone = phone;
this.text = text;
this.nature = nature; // incoming OR outgoing
}
public int getId(){return this.id;}
public String getPhone(){return this.phone;}
public String getText(){return this.text;}
public String getNature(){return this.nature;}
}
Problem:
I want the incoming messages to be located on the left. And outgoing messages are located on the right.
To do this, I slightly changed the static method of the MessageViewHolder class:
//The method decides which design to choose for the message bubble.
static MessageViewHolder create(ViewGroup parent, Message current) {
View view;
if (current.getNature().equals("outgoing"))
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.recyclerview_item_outgoing, parent, false);
else view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.recyclerview_item_incoming, parent, false);
return new MessageViewHolder(view);
}
But the problem is that I do not know how I can correctly pass the Message objects to this method?
As you can see, I tried to pass the Message object in the MessageListAdapter class:
#Override
public MessageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
countMessages = getItemCount();
// I need to pass the create index method of the current message.!!!!!!!!!!
// The getItem() function returns a Message object.
return MessageViewHolder.create(parent, getItem(idMessage));
}
#Override
public void onBindViewHolder(MessageViewHolder holder, int position) {
Message current = getItem(position);
holder.bind(current.getPhone() ,current.getText()); // Бинтим только тело телефон и сообщение!
idMessage = position+1;
if(idMessage >= countMessages) idMessage = 0;
}
I added 2 static variable (idMessage, countMessages), but this worked don't correctly.
How I can add Message object for method MessageViewHolder.create(...) ?
Project on GitHub: https://github.com/MinorityMeaning/HelloApp
The getItemViewType() is the right place for determining the item layout. So you need to move the logic there, so override it in the adapter:
#Override
public int getItemViewType(int position) {
if (getItem(position).getNature().equals("outgoing"))
return R.layout.recyclerview_item_outgoing;
else
return R.layout.recyclerview_item_incoming;
}
And that being reflected in the viewType parameter of onCreateViewHolder(), so it holds the right layout for the current item. So you'd pass that to the ViewHolder:
#Override
public MessageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return MessageViewHolder.create(parent, viewType);
}
And In ViewHolder set that as your layout:
static MessageViewHolder create(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(viewType, parent, false);
return new MessageViewHolder(view);
}
I am designing a relatively complex UI, i have searched stackoverflow and haven't found similar design. There could be many approaches to this, but i would like to ask expert opionions on how to achieve this and i would like to share my approach and make sure i am doing it the right way. My approach is that i have created a recycleview with header and inside header recycleview i am using an expandable recycleview library developed by h6ah4i (taken from github). Please let me know if there's a better approach to this.
The following image preview is a live mockup of final result i would like to get. It's not the actual screen. My question is what is the best way to achieve this, should i use expandable recycleview or expandable listview in recycleview header. I appreciate any answer as approaches or libraries it doesn't have to be similar to my code. Any suggestions are welcomed. I hope this post will also help other people like me in search of similar solution.
RecycleView Adapter
public class RecycleAdapterPlantSearch extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int TYPE_HEADER = 0;
private static final int TYPE_ITEM = 1;
private List<Plants> plantsList;
private Context context;
private OnItemClickListener onItemClickListener;
public RecycleAdapterPlantSearch(Context context, List<Plants> plantsList, OnItemClickListener onClickListener) {
this.context = context;
this.plantsList = plantsList;
onItemClickListener = onClickListener;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_ITEM) {
// Here Inflating your recyclerview item layout
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_view_plant_search_plant_item, parent, false);
return new ItemViewHolder(itemView, onItemClickListener);
} else if (viewType == TYPE_HEADER) {
// Here Inflating your header view
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_view_plant_search_header, parent, false);
return new HeaderViewHolder(itemView, onItemClickListener);
} else return null;
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
/*
position 0 is for header
*/
if (holder instanceof HeaderViewHolder) {
// setheadersdata_flag = true;
HeaderViewHolder headerViewHolder = (HeaderViewHolder) holder;
// You have to set your header items values with the help of model class and you can modify as per your needs
// Setup expandable feature and RecyclerView
RecyclerViewExpandableItemManager expMgr = new RecyclerViewExpandableItemManager(null);
SimpleDemoExpandableItemAdapter.OnListItemClickMessageListener clickListener = message -> {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
};
List<BadgesVM> badgesVMList = null;
badgesVMList = new ArrayList() {{
add(new BadgesVM("447", "Bienenfreundlich", "bienenfreundlich", false));
add(new BadgesVM("320,322", "Vogelfreundlich", "vogelfreundlich", false));
add(new BadgesVM("321", "Insektenfreundlich", "insektenfreundlich", false));
add(new BadgesVM("445", "Ökologisch wertvoll", "oekologisch", false));
add(new BadgesVM("531", "Schmetterlings freundlich", "schmetterlings", false));
add(new BadgesVM("530", "Heimische Pflanze'", "heimische Pflanze'", false));
}};
// Create wrapped adapter: MyItemAdapter -> expMgr.createWrappedAdapter -> MyHeaderFooterAdapter
RecyclerView.Adapter adapter;
adapter = new SimpleDemoExpandableItemAdapter(context, expMgr,badgesVMList, clickListener);
adapter = expMgr.createWrappedAdapter(adapter);
//adapter = new DemoHeaderFooterAdapter(adapter, null);
headerViewHolder.recyclerViewExpandable.setAdapter(adapter);
headerViewHolder.recyclerViewExpandable.setLayoutManager(new LinearLayoutManager(context));
// NOTE: need to disable change animations to ripple effect work properly
((SimpleItemAnimator) headerViewHolder.recyclerViewExpandable.getItemAnimator()).setSupportsChangeAnimations(false);
expMgr.attachRecyclerView(headerViewHolder.recyclerViewExpandable);
} else if (holder instanceof ItemViewHolder) {
final ItemViewHolder itemViewHolder = (ItemViewHolder) holder;
itemViewHolder.plantDescText.setText(plantsList.get(position - 1).getDescription());
RequestOptions options = new RequestOptions()
.centerCrop()
.placeholder(R.drawable.background_small);
String imageUrl = APP_URL.BASE_ROUTE_INTERN + plantsList.get(position - 1).getImages().get(0).getSrcAttr();
Glide.with(context).load(imageUrl).apply(options).into(itemViewHolder.plantImg);
}
}
#Override
public int getItemViewType(int position) {
if (position == 0) {
return TYPE_HEADER;
}
return TYPE_ITEM;
}
#Override
public long getItemId(int position) {
return position;
}
// getItemCount increasing the position to 1. This will be the row of header
#Override
public int getItemCount() {
return plantsList.size() + 1;
}
public interface OnItemClickListener {
void OnItemClickListener(View view, int position);
void RecycleViewExtraDetails(ChipGroup chipGroup);
void nestedRecycleViewsSpecialOdd(RecyclerView nestedRecycleView);
}
private class HeaderViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private TextView searchNameTxt, searchFamilyTxt, plantGroupTxt, plantFamilySearchTxt, ecologyFilterTxt,
frostSearchTxt;
private ChipGroup chipGroup;
private Button filterSearchBtn;
private CardView ecologyCv;
private CardView detailSearchCv;
private RecyclerView recyclerViewExpandable;
public HeaderViewHolder(View headerView, OnItemClickListener onItemClickListener) {
super(headerView);
searchNameTxt = headerView.findViewById(R.id.textView_plant_search_header_plant_search);
searchFamilyTxt = headerView.findViewById(R.id.textView_plant_search_header_plant_search);
ecologyCv = headerView.findViewById(R.id.cardView_plant_search_header_ecology);
detailSearchCv = headerView.findViewById(R.id.cardView_plant_search_header_detail_search);
plantGroupTxt = headerView.findViewById(R.id.textView_plant_search_header_plant_group);
plantFamilySearchTxt = headerView.findViewById(R.id.textView_plant_search_header_plant_family);
ecologyFilterTxt = headerView.findViewById(R.id.textView_plant_search_header_ecology_filter);
frostSearchTxt = headerView.findViewById(R.id.textView_plant_search_header_frost_filter);
chipGroup = headerView.findViewById(R.id.chip_group_plant_search_header);
filterSearchBtn = headerView.findViewById(R.id.button_plant_search_header_filter_search);
recyclerViewExpandable = headerView.findViewById(R.id.expandable_list_view_plant_search);
searchNameTxt.setOnClickListener(this);
searchFamilyTxt.setOnClickListener(this);
ecologyCv.setOnClickListener(this);
detailSearchCv.setOnClickListener(this);
plantGroupTxt.setOnClickListener(this);
plantFamilySearchTxt.setOnClickListener(this);
ecologyFilterTxt.setOnClickListener(this);
filterSearchBtn.setOnClickListener(this);
frostSearchTxt.setOnClickListener(this);
}
#Override
public void onClick(View view) {
onItemClickListener.OnItemClickListener(view, getAdapterPosition());
onItemClickListener.RecycleViewExtraDetails(chipGroup);
}
}
public class ItemViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private Button readMoreBtn;
private TextView plantDescText;
private ImageView plantImg;
public ItemViewHolder(View itemView, OnItemClickListener onItemClickListener) {
super(itemView);
plantDescText = itemView.findViewById(R.id.textView_plant_search_plants_item_description_text);
readMoreBtn = itemView.findViewById(R.id.button_plant_search_plant_item_read_more);
plantImg = itemView.findViewById(R.id.imageView_plant_search_plants_item_plant_image);
readMoreBtn.setOnClickListener(this);
}
#Override
public void onClick(View view) {
onItemClickListener.OnItemClickListener(view, getAdapterPosition() - 1);
}
}
}
nested header recycleview
public class SimpleDemoExpandableItemAdapter extends AbstractExpandableItemAdapter<SimpleDemoExpandableItemAdapter.MyGroupViewHolder,
SimpleDemoExpandableItemAdapter.MyChildViewHolder> implements View.OnClickListener {
RecyclerViewExpandableItemManager mExpandableItemManager;
List<MyBaseItem> mItems;
OnListItemClickMessageListener mOnItemClickListener;
List<BadgesVM> badgesVMList;
Context context;
static class MyBaseItem {
public final int id;
public final String text;
public MyBaseItem(int id, String text) {
this.id = id;
this.text = text;
}
}
static abstract class MyBaseViewHolder extends AbstractExpandableItemViewHolder {
TextView textView;
Slider frostSlider;
RecyclerView detailRecycleView;
public MyBaseViewHolder(View itemView) {
super(itemView);
textView = itemView.findViewById(android.R.id.text1);
frostSlider = itemView.findViewById(R.id.slider_plant_search_expandable);
detailRecycleView = itemView.findViewById(R.id.recycle_view_plant_search_detail_search);
}
}
static class MyGroupViewHolder extends MyBaseViewHolder {
public MyGroupViewHolder(View itemView) {
super(itemView);
}
}
static class MyChildViewHolder extends MyBaseViewHolder {
public MyChildViewHolder(View itemView) {
super(itemView);
}
}
public SimpleDemoExpandableItemAdapter(Context context, RecyclerViewExpandableItemManager expMgr, List<BadgesVM> badgesVMList, OnListItemClickMessageListener clickListener) {
mExpandableItemManager = expMgr;
mOnItemClickListener = clickListener;
this.badgesVMList = badgesVMList;
this.context = context;
setHasStableIds(true); // this is required for expandable feature.
mItems = new ArrayList<>();
mItems.add(new MyBaseItem(0, "Filter nach ökologischen Kriterien"));
mItems.add(new MyBaseItem(1, "Frosthärte"));
mItems.add(new MyBaseItem(2, "Detailsuche"));
}
#Override
public int getGroupCount() {
return mItems.size();
}
#Override
public int getChildCount(int groupPosition) {
int childCount = 0;
int groupId = mItems.get(groupPosition).id;
if (groupId == 0) {
childCount = badgesVMList.size();
} else if (groupId == 1) {
childCount = 1; //contains only one item
} else if (groupId == 2) {
childCount = 1; //contains only one item
}
return childCount;
}
#Override
public long getGroupId(int groupPosition) {
// This method need to return unique value within all group items.
return mItems.get(groupPosition).id;
}
#Override
public long getChildId(int groupPosition, int childPosition) {
// This method need to return unique value within the group.
int groupId = mItems.get(groupPosition).id;
int childId = 0;
if (groupId == 0) {
badgesVMList.get(childPosition).getId();
} else if (groupId == 1) {
childId = 0;
} else if (groupId == 2) {
childId = 0;
}
return childId;
}
#Override
#NonNull
public MyGroupViewHolder onCreateGroupViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_group_item_for_expandable_minimal, parent, false);
MyGroupViewHolder vh = new MyGroupViewHolder(v);
vh.itemView.setOnClickListener(this);
return vh;
}
#Override
#NonNull
public MyChildViewHolder onCreateChildViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_child_item_for_expandable_minimal, parent, false);
MyChildViewHolder vh = new MyChildViewHolder(v);
vh.itemView.setOnClickListener(this);
return vh;
}
#Override
public void onBindGroupViewHolder(#NonNull MyGroupViewHolder holder, int groupPosition, int viewType) {
MyBaseItem group = mItems.get(groupPosition);
holder.textView.setText(group.text);
}
#Override
public void onBindChildViewHolder(#NonNull MyChildViewHolder holder, int groupPosition, int childPosition, int viewType) {
int groupId = mItems.get(groupPosition).id;
if (groupId == 0) {
BadgesVM badgesVM = badgesVMList.get(childPosition);
holder.textView.setVisibility(View.VISIBLE);
holder.frostSlider.setVisibility(View.GONE);
holder.detailRecycleView.setVisibility(View.GONE);
holder.textView.setText(badgesVM.getName());
} else if (groupId == 1) {
holder.textView.setVisibility(View.GONE);
holder.frostSlider.setVisibility(View.VISIBLE);
holder.detailRecycleView.setVisibility(View.GONE);
} else if (groupId == 2) {
holder.textView.setVisibility(View.GONE);
holder.frostSlider.setVisibility(View.GONE);
holder.detailRecycleView.setVisibility(View.VISIBLE);
// Setup expandable feature and RecyclerView
RecyclerViewExpandableItemManager expMgr = new RecyclerViewExpandableItemManager(null);
DetailSearchExpandableItemAdapter.OnListItemClickMessageListener clickListener = message -> {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
};
List<BadgesVM> badgesVMList = null;
badgesVMList = new ArrayList() {{
add(new BadgesVM("447", "Bienenfreundlich", "bienenfreundlich", false));
add(new BadgesVM("320,322", "Vogelfreundlich", "vogelfreundlich", false));
add(new BadgesVM("321", "Insektenfreundlich", "insektenfreundlich", false));
add(new BadgesVM("445", "Ökologisch wertvoll", "oekologisch", false));
add(new BadgesVM("531", "Schmetterlings freundlich", "schmetterlings", false));
add(new BadgesVM("530", "Heimische Pflanze'", "heimische Pflanze'", false));
}};
// Create wrapped adapter: MyItemAdapter -> expMgr.createWrappedAdapter -> MyHeaderFooterAdapter
RecyclerView.Adapter adapter2;
adapter2 = new DetailSearchExpandableItemAdapter(context, expMgr, badgesVMList, clickListener);
adapter2 = expMgr.createWrappedAdapter(adapter2);
//adapter = new DemoHeaderFooterAdapter(adapter, null);
holder.detailRecycleView.setAdapter(adapter2);
holder.detailRecycleView.setLayoutManager(new LinearLayoutManager(context));
// NOTE: need to disable change animations to ripple effect work properly
((SimpleItemAnimator) holder.detailRecycleView.getItemAnimator()).setSupportsChangeAnimations(false);
expMgr.attachRecyclerView(holder.detailRecycleView);
}
}
#Override
public boolean onCheckCanExpandOrCollapseGroup(#NonNull MyGroupViewHolder holder, int groupPosition, int x, int y, boolean expand) {
// handles click event manually (to show Snackbar message)
return false;
}
#Override
public void onClick(View v) {
RecyclerView rv = RecyclerViewAdapterUtils.getParentRecyclerView(v);
RecyclerView.ViewHolder vh = rv.findContainingViewHolder(v);
int rootPosition = vh.getAdapterPosition();
if (rootPosition == RecyclerView.NO_POSITION) {
return;
}
// need to determine adapter local flat position like this:
RecyclerView.Adapter rootAdapter = rv.getAdapter();
int localFlatPosition = WrapperAdapterUtils.unwrapPosition(rootAdapter, this, rootPosition);
long expandablePosition = mExpandableItemManager.getExpandablePosition(localFlatPosition);
int groupPosition = RecyclerViewExpandableItemManager.getPackedPositionGroup(expandablePosition);
int childPosition = RecyclerViewExpandableItemManager.getPackedPositionChild(expandablePosition);
String message;
if (childPosition == RecyclerView.NO_POSITION) {
// Clicked item is a group!
// toggle expand/collapse
if (mExpandableItemManager.isGroupExpanded(groupPosition)) {
mExpandableItemManager.collapseGroup(groupPosition);
message = "COLLAPSE: Group " + groupPosition;
} else {
mExpandableItemManager.expandGroup(groupPosition);
message = "EXPAND: Group " + groupPosition;
}
} else {
// Clicked item is a child!
message = "CLICKED: Child " + groupPosition + "-" + childPosition;
}
mOnItemClickListener.onItemClicked(message);
}
public interface OnListItemClickMessageListener {
void onItemClicked(String message);
}
}
You were right to search a library that does most of the work for you, but I don't like the library you picked. It does not seem very flexible and concise. I suggest to take a look at Groupie, its API is pretty clean. Also check Reddit for some discussion on libraries.
If you want to write it yourself I think you can solve it without nested Adapter's. Just create an 'expandable group' item type. Then in getItemCount() you count all items and their nested items (when expanded). Take a look at the Groupie source code.
Some additional feedback on your code:
I would explicitly add the header to the list of items you give to your adapter. So instead of a List<Plants>, you rather provide a List<Item> and have a HeaderItem and PlantsItem. This way you have a clear separation between your domain models (Plants) and view models (the items) in your adapter.
Your onBindViewHolder() method does way too much. Let your ViewHolder subclasses take care of that. Create an abstract ViewHolder with an abstract bindTo(Item item) method. Then in your HeaderViewHolder subclass it and do the actual work (after an instanceof check).
Have a look at view binding, it can make your code more concise. (So does Kotlin.)
You can use ConcatAdapter to have multiple adapters with ViewHolders that hold different type of layouts even with the ones that contain RecyclerViews, i used in my last project and it works fine, you can check it out here, dashboard module uses multiple adapters to have different type of layouts.
You can also use the approach they used in Google iosched app to have one adapter with multiple layouts in better way where you move logic from adapter to ViewHolders and their wrapper class ViewBinders. ViewBinder is responsible of
calling onViewHolder, onCreateViewHolder and bind data type to a ViewBinder and ViewBinder to a layout. There is an article about how to use it in medium, i will post the link if i can find it. You can also check out this sample i created for animations but used ViewBinders in a simple form to create different type of layouts.
Below is the type of data and layout i wish to show in GridLayout and in which order
val data = mutableListOf<Any>().apply {
// Add Vector Drawables
add(HeaderModel("Animated Vector Drawable"))
add(AVDModel(R.drawable.avd_likes))
add(AVDModel(R.drawable.avd_settings))
add(HeaderModel("Seekable Vector Drawable"))
add(SeekableVDModel(R.drawable.avd_compass_rotation))
add(SeekableVDModel(R.drawable.avd_views))
add(SeekableVDModel(R.drawable.avd_hourglass))
add(HeaderModel("Clocks"))
add(AVDModel(R.drawable.avd_clock_alarm))
add(AVDModel(R.drawable.avd_clock_clock))
add(AVDModel(R.drawable.avd_clock_stopwatch))
}
These are correspond type of data i want to use in my RecyclerView, it's the types and binding to ViewHolder and layout in these classes.
private fun createViewBinders(): HashMap<ItemClazz, MappableItemBinder> {
val avdViewBinder = AVDViewBinder()
val seekableVDViewBinder = SeekableVDViewBinder()
val headViewBinder = HeaderViewBinder()
return HashMap<ItemClazz, MappableItemBinder>()
.apply {
put(
avdViewBinder.modelClazz,
avdViewBinder as MappableItemBinder
)
put(
seekableVDViewBinder.modelClazz,
seekableVDViewBinder as MappableItemBinder
)
put(
headViewBinder.modelClazz,
headViewBinder as MappableItemBinder
)
}
}
And set the data List to adapter and let adapter call corresponding layout that is bound to data
val dataList:List<Any> = getVectorDrawableItemList()
val recyclerView = findViewById<RecyclerView>(R.id.recyclerView)
val adapter = MultipleViewBinderListAdapter(
createViewBinders(),
RecyclerView.Adapter.StateRestorationPolicy.ALLOW
).apply {
submitList(dataList)
}
For the expandable list, iosched app good way of doing it, there is video about how to animate expandable items in RecyclerVİew here. You can set state in ViewHolder and even use MotionLayout for animating from collapsed to expandable state. All can be done without any third party library and very clean way.
I know how to create a ListView in Android but I need some kind of accordion list view in Android. Something like this:
The accordion list should have a section header and should toggle when clicking on the section header.
How can I build such an accordion ListView?
You could use ExpandableListView. Documentation here
you change child_view.xml content.
http://www.learn-android-easily.com/2013/07/android-expandablelistview-example.html
http://theopentutorials.com/tutorials/android/listview/android-expandable-list-view-example/
I have build a super light Accordion list recently via Constraint layout . It's worth to have a look at :
https://github.com/draxdave/ConstraintAccordion
Why would you use ListView? Android has something new now called RecyclerView which takes place for the ListView: https://developer.android.com/reference/android/support/v7/widget/RecyclerView.html
Here is the way of making a header using RecyclerView:
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
public class HeaderAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int TYPE_HEADER = 0;
private static final int TYPE_ITEM = 1;
String[] data;
public HeaderAdapter(String[] data) {
this.data = data;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_ITEM) {
//inflate your layout and pass it to view holder
return new VHItem(null);
} else if (viewType == TYPE_HEADER) {
//inflate your layout and pass it to view holder
return new VHHeader(null);
}
throw new RuntimeException("there is no type that matches the type " + viewType + " + make sure your using types correctly");
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof VHItem) {
String dataItem = getItem(position);
//cast holder to VHItem and set data
} else if (holder instanceof VHHeader) {
//cast holder to VHHeader and set data for header.
}
}
#Override
public int getItemCount() {
return data.length + 1;
}
#Override
public int getItemViewType(int position) {
if (isPositionHeader(position))
return TYPE_HEADER;
return TYPE_ITEM;
}
private boolean isPositionHeader(int position) {
return position == 0;
}
private String getItem(int position) {
return data[position - 1];
}
class VHItem extends RecyclerView.ViewHolder {
TextView title;
public VHItem(View itemView) {
super(itemView);
}
}
class VHHeader extends RecyclerView.ViewHolder {
Button button;
public VHHeader(View itemView) {
super(itemView);
}
}
}
Link on git: https://gist.github.com/hister/d56c00fb5fd2dfaf279b
I've a problem with listview in android, I've created a list view that takes data from SQLite database with a custom ArrayAdapter
I want to display an image view when user choose an item, but when I click on an item, the image (check mark) shows in 3 other items
I don't know where is the problem exactly, here is my code for adapter :
import info.androidhive.tabsswipe.R;
import java.util.List;
import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.itdinamik.tabswipe.CompareVehicle;
import com.itdinamik.vcompare.MySQLiteHelper;
import com.itdinamik.vcompare.Vehicle;
public class ComperAdapter extends ArrayAdapter<Vehicle>{
List<Vehicle> data;
Context context;
int layoutResID;
Vehicle itemdata;
MySQLiteHelper dbhelper;
public ComperAdapter(Context context, int layoutResourceId, List<Vehicle> data) {
super(context, layoutResourceId, data);
this.data=data;
this.context=context;
this.layoutResID=layoutResourceId;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final NewsHolder holder;
View row = convertView;
dbhelper = new MySQLiteHelper(context);
if(row == null)
{
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
row = inflater.inflate(layoutResID, parent, false);
holder = new NewsHolder();
holder.itemNameTitle = (TextView)row.findViewById(R.id.VehicleTxt);
holder.itemNameScore = (TextView)row.findViewById(R.id.Score);
holder.CheckedMark=(ImageView)row.findViewById(R.id.Checked);
holder.Vehicle=(ImageView)row.findViewById(R.id.Vehicle);
holder.RL = (RelativeLayout)row.findViewById(R.id.Rv);
row.setTag(holder);
}
else
{
holder = (NewsHolder)row.getTag();
}
//Toast.makeText(getContext(), String.valueOf(position +" - " + CompareVehicle.ClickedItem), Toast.LENGTH_SHORT).show();
if(CompareVehicle.ItemClieckd) {
if(position == CompareVehicle.ClickedItem) {
Log.w("Position", String.valueOf(position));
holder.CheckedMark.setVisibility(View.VISIBLE);
holder.RL.setBackgroundColor(Color.rgb(201, 50, 39));
}
}
itemdata = data.get(position);
holder.itemNameTitle.setText(itemdata.getTitle() + " - " + itemdata.getKraj() + " - "+ String.valueOf(position) + " - " + CompareVehicle.ClickedItem);
double totaldefault = itemdata.getOhranjenost()*0.25+itemdata.getPrevozeni()*0.16+
itemdata.getServis()*0.14+ itemdata.getCena()*0.13+
itemdata.getPoraba()*0.11+ itemdata.getStarost()*0.08+
itemdata.getDodatna()*0.07+ itemdata.getCenaZav()*0.06;
holder.itemNameScore.setText(String.format("%.1f",totaldefault));
return row;
}
static class NewsHolder{
TextView itemNameTitle;
TextView itemNameScore;
ImageView CheckedMark, Vehicle;
RelativeLayout RL;
}
}
and this one is for my fragment that i use to show my list view
import info.androidhive.tabsswipe.R;
import java.util.ArrayList;
import java.util.List;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.Toast;
import com.itdinamik.tabswipe.adapter.ComperAdapter;
import com.itdinamik.vcompare.MySQLiteHelper;
import com.itdinamik.vcompare.Vehicle;
public class CompareVehicle extends Fragment{
ViewPager mViewPager;
ArrayList<Vehicle> DataList;
static MySQLiteHelper dbhelper;
ComperAdapter adapter;
List<Vehicle> itemData;
ListView lv;
Button CompareButton;
int ClickedNum = 0;
public static int ClickedItem;
public static boolean ItemClieckd = false;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_compare_vehicle, container, false);
lv = (ListView)rootView.findViewById(R.id.CompareList);
CompareButton = (Button)rootView.findViewById(R.id.CompareButton);
dbhelper = new MySQLiteHelper(getActivity());
// get all vehicles
itemData = dbhelper.getAllVehicles();
adapter=new ComperAdapter(getActivity(),R.layout.list_single,itemData);
lv.setAdapter(adapter);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int position,
long arg3) {
// TODO Auto-generated method stub
ClickedItem = position;
ItemClieckd = true;
ClickedNum += 1;
adapter.notifyDataSetChanged();
/*RelativeLayout Rl = (RelativeLayout)arg1.findViewById(R.id.Rv);
ImageView CheckImg = (ImageView)arg1.findViewById(R.id.Checked);
Rl.setBackgroundColor(Color.rgb(201, 50, 39));
CheckImg.setVisibility(View.VISIBLE);*/
//Toast.makeText(getActivity(), String.valueOf(mSelectedItem), Toast.LENGTH_LONG).show();
}
});
CompareButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (ClickedNum < 2) {
Toast.makeText(getActivity(), "Please mark at least 2 items to compare them", Toast.LENGTH_LONG).show();
}
}
});
return rootView;
}
}
thank you
To avoid issues with view recycling in ListViews etc, I include a boolean for checked state in the item data List supplied to the constructor of the ArrayAdapter. I also provide my own interface for handling things like click events on child Views contained in my custom list item layout.
In my example below we handle a checkbox which can be clicked and also a label which can be long clicked:
public class MyListAdapter extends ArrayAdapter<MyItem> {
// interface for handling item child view events
public interface MyListAdapterListener {
void onItemCheckClicked(int index);
void onItemLabelLongClicked(int index);
}
private MyListAdapterListener mMyListAdapterListener;
int layoutResID;
// Constructor
public MyListAdapter(Context context, int resource, List<MyItem> myItems) {
super(context, resource, myItems);
layoutResID = resource;
}
public void setMyListAdapterListener(MyListAdapterListener listener) {
this.mMyListAdapterListener = listener;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// setup the row
View row;
if (convertView == null) {
LayoutInflater inflater = LayoutInflater.from(getContext());
row = inflater.inflate(layoutResID, null);
} else {
row = convertView;
}
// setup the ViewHolder for this item
ViewHolder holder = (ViewHolder) row.getTag();
if (holder == null) {
holder = new ViewHolder(row);
row.setTag(holder);
}
// setup this item's label view
holder.label.setText(getItem(position).label);
// tag this item's label view with position so it can be retrieved in the onLongClick
holder.label.setTag(position);
// set the OnLongClickListener for the this item's label view
holder.label.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
if (mActivityListListener != null) {
// retrieve position from the view's tag, and trigger the listeners onItemLabelLongClicked method
mActivityListListener.onItemLabelLongClicked((Integer)v.getTag());
}
return false;
}
});
// setup this item's checkbox view
holder.checkbox.setChecked(getItem(position).myItemCheckBoolean);
// tag this item's checkbox view with position so it can be retrieved in the onClick
holder.checkbox.setTag(position);
// set the OnClickListener for the this item's checkbox view
holder.checkbox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mMyListAdapterListener != null) {
// retrieve position from the view's tag, and trigger the listeners onItemCheckClicked method
mMyListAdapterListener.onItemCheckClicked((Integer) v.getTag());
}
}
});
return row;
}
class ViewHolder {
CheckBox checkbox = null;
TextView label = null;
ViewHolder(View row) {
this.checkbox = (CheckBox) row.findViewById(R.id.check_box);
this.label = (TextView) row.findViewById(R.id.item_label);
}
}
}
The MyItem class:
public class MyItem {
public String label;
public boolean myItemCheckBoolean;
}
Using the ArrayAdapter:
public class MyFragment extends Fragment {
....
private List<MyItem> myItems = new ArrayList<MyItem>();
....
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment__my_list, container, false);
lv = (ListView)rootView.findViewById(R.id.my_list);
// For example purposes, fill myItems with dummy data setting all checkboxes initially to false
for (int i = 0; i < 10; i++) {
MyItem myItem = new MyItem();
myItem.label = "Item " + i;
myItem.myItemCheckBoolean = false;
myItems.add(myItem);
}
MyListAdapter adapter = new MyListAdapter(getActivity(), R.layout.my_list_item, myItems);
adapter.setMyListAdapterListener( new MyListAdapter.MyListAdapterListener() {
#Override
public void onItemCheckClicked(int index) {
Log.d("MyFragment", "Item " + index + " Check Clicked");
// toggle the item's boolean
myItems.get(index).myItemCheckBoolean = !myItems.get(index).myItemCheckBoolean;
}
#Override
public void onItemLabelLongClicked(int index) {
Log.d("MyFragment", "Item " + index + " Label LongClicked");
}
}
lv.setAdapter(adapter);
....
return rootView;
}
Additional:
In response to your comment, you can use the adapter to customize the display of your list items as you wish. The version below shows how you might modify the adapter to use an ImageView instead of a CheckBox, and also changes the background color:
public class MyListAdapter extends ArrayAdapter<MyItem> {
// interface for handling item child view events
public interface MyListAdapterListener {
void onItemCheckClicked(int index);
void onItemLabelLongClicked(int index);
}
private MyListAdapterListener mMyListAdapterListener;
int layoutResID;
// Constructor
public MyListAdapter(Context context, int resource, List<MyItem> myItems) {
super(context, resource, myItems);
layoutResID = resource;
}
public void setMyListAdapterListener(MyListAdapterListener listener) {
this.mMyListAdapterListener = listener;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// setup the row
View row;
if (convertView == null) {
LayoutInflater inflater = LayoutInflater.from(getContext());
row = inflater.inflate(layoutResID, null);
} else {
row = convertView;
}
// setup the ViewHolder for this item
ViewHolder holder = (ViewHolder) row.getTag();
if (holder == null) {
holder = new ViewHolder(row);
row.setTag(holder);
}
// setup this item's label view
holder.label.setText(getItem(position).label);
// tag this item's label view with position so it can be retrieved in the onLongClick
holder.label.setTag(position);
// set the OnLongClickListener for the this item's label view
holder.label.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
if (mActivityListListener != null) {
// retrieve position from the view's tag, and trigger the listeners onItemLabelLongClicked method
mActivityListListener.onItemLabelLongClicked((Integer)v.getTag());
}
return false;
}
});
// setup this item's image view based on the current state of the boolean
if (getItem(position).myItemCheckBoolean) {
holder.image.setImageResource(R.drawable.image_a);
} else {
holder.image.setImageResource(R.drawable.image_b);
}
// tag this item's image view with position so it can be retrieved in the onClick
holder.image.setTag(position);
// set the OnClickListener for the this item's image view
holder.image.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mMyListAdapterListener != null) {
// retrieve position from the view's tag, and trigger the listeners onItemCheckClicked method
mMyListAdapterListener.onItemCheckClicked((Integer) v.getTag());
}
}
});
// setup this item's background based on the current state of the boolean
if (getItem(position).myItemCheckBoolean) {
holder.layout.setBackgroundColor(Color.red);
} else {
holder.layout.setBackgroundColor(Color.white);
}
return row;
}
class ViewHolder {
ImageView image = null;
TextView label = null;
RelativeLayout layout = null;
// constructor
ViewHolder(View row) {
this.image = (ImageView) row.findViewById(R.id.item_image);
this.label = (TextView) row.findViewById(R.id.item_label);
this.layout = (RelativeLayout) row.findViewById(R.id.item_layout)
}
}
}