android - RecyclerView causes issue when recycling -
i have list of item created using recyclerview. when user clicks on 1 of them change background color of selected item. problem is, when scroll through items, , recycled, of items selected item's background color (which wrong). here can see adapter's code:
public class orderadapter extends recyclerview.adapter<orderadapter.viewholder> { private static final string selected_color = "#ffedcc"; private list<ordermodel> morders; public orderadapter() { this.morders = new arraylist<>(); } public void setorders(list<ordermodel> orders) { morders = orders; } public void addorders(list<ordermodel> orders) { morders.addall(0, orders); } public void addorder(ordermodel order) { morders.add(0, order); } @override public viewholder oncreateviewholder(viewgroup parent, int viewtype) { context context = parent.getcontext(); layoutinflater inflater = layoutinflater.from(context); // inflate custom layout view contactview = inflater.inflate(r.layout.order_main_item, parent, false); // return new holder instance viewholder viewholder = new viewholder(contactview); return viewholder; } @override public void onbindviewholder(final viewholder viewholder, final int position) { final ordermodel ordermodel = morders.get(position); // set item views based on data model textview customername = viewholder.customernametext; simpledateformat simpledateformat = new simpledateformat("mm/dd/yyyy' 'hh:mm:ss:s"); string time = simpledateformat.format(ordermodel.getordertime()); customername.settext(time); textview ordernumber = viewholder.ordernumbertext; ordernumber.settext("order no: " + ordermodel.getordernumber()); button button = viewholder.acceptbutton; button.setonclicklistener(new view.onclicklistener() { @override public void onclick(view v) { viewholder.useractions.acceptbuttonclicked(position); } }); final linearlayout orderitem = viewholder.orderitem; orderitem.setonclicklistener(new view.onclicklistener() { @override public void onclick(view v) { viewholder.useractions.itemclicked(ordermodel); viewholder.orderitem.setbackgroundcolor(color.parsecolor(selected_color)); } }); } @override public int getitemcount() { return morders.size(); } public static class viewholder extends recyclerview.viewholder implements ordercontract.view { public textview customernametext; public button acceptbutton; public textview ordernumbertext; public ordercontract.useractions useractions; public linearlayout orderitem; public viewholder(view itemview) { super(itemview); useractions = new orderpresenter(this); customernametext = (textview) itemview.findviewbyid(r.id.customer_name); acceptbutton = (button) itemview.findviewbyid(r.id.accept_button); ordernumbertext = (textview) itemview.findviewbyid(r.id.order_number); orderitem = (linearlayout) itemview.findviewbyid(r.id.order_item_selection); } @override public void removeitem() { } }
the problem recyclerview
recycling behavior assign out of screen viewholder
items new items coming displayed on screen. not suggest bind logic based on viewholder
object in above answers. cause problem. should build logic based on state of data object not viewholder
object never know when gets recycled.
suppose save state boolean isselected in viewholder
check, , if true, same state there new item when viewholder
recycled.
better way above holding state in datamodel object. in case boolean isselected.
sample example like
package chhimwal.mahendra.multipleviewrecyclerproject; import android.content.context; import android.support.v7.widget.recyclerview; import android.view.layoutinflater; import android.view.view; import android.view.viewgroup; import android.support.v7.widget.cardview; import android.widget.textview; import java.util.list; /** * created mahendra.chhimwal on 12/10/2015. */ public class myrecyclerviewadapter extends recyclerview.adapter<myrecyclerviewadapter.viewholder> { private context mcontext; private list<datamodel> mrviewdatalist; public myrecyclerviewadapter(context context, list<datamodel> rviewdatalist) { this.mcontext = context; this.mrviewdatalist = rviewdatalist; } @override public myrecyclerviewadapter.viewholder oncreateviewholder(viewgroup parent, int viewtype) { layoutinflater inflater = layoutinflater.from(parent.getcontext()); view view = inflater.inflate(r.layout.item_recycler_view, parent, false); return new viewholder(view); } @override public void onbindviewholder(viewholder holder, int position) { holder.binddatawithviewholder(mrviewdatalist.get(position)); } @override public int getitemcount() { return mrviewdatalist != null ? mrviewdatalist.size() : 0; } public class viewholder extends recyclerview.viewholder { private textview textview; private linearlayout llview; private datamodel mdataitem=null; public viewholder(view itemview) { super(itemview); llview=(linearlayout)itemview.findviewbyid(r.id.ll_root_view); textview = (textview) itemview.findviewbyid(r.id.tvitemname); cvitemview.setonclicklistener(new view.onclicklistener() { @override public void onclick(view v) { // 1 should handle onclick of event here based on dataitem i.e. mdataitem in case. // that.. /* intent intent = new intent(mcontext,resultactivity.class); intent.putextra("my_data",mdataitem); //if want pass data. intent.putextra("clicked_item_postion",getadapterposition()); // if 1 want selected item position startactivity(intent);*/ toast.maketext(mcontext,"you clicked item number "+viewholder.this.getadapterposition(),toast.lenth_short).show(); } }); } //this clean method bind data viewholder. dirty things on view based on dataitem. //must called onbindviewholder(),with dataitem. in our case dataitem string object. public void binddatawithviewholder(datamodel dataitem){ this.mdataitem=dataitem; if(mdataitem.isselected()){ llview.setbackgroundcolor(color.parsecolor(selcted_color); }else{ llview.setbackgroundcolor(color.parsecolor(default_color); } //other view binding logics setting text , loading image etc. textview.settext(mdataitem); } } }
as @gabriel asked in comment,
what if 1 want select single item @ time?
in case, again 1 should not save selected item state in viewholder
object, same gets recycled , cause problem. better way have field int selecteditemposition
in adapter
class not viewholder
. following code snippet show it.
public class myrecyclerviewadapter extends recyclerview.adapter<myrecyclerviewadapter.viewholder> { private context mcontext; private list<datamodel> mrviewdatalist; //variable hold selected item position private int mselecteditemposition = -1; public myrecyclerviewadapter(context context, list<datamodel> rviewdatalist) { this.mcontext = context; this.mrviewdatalist = rviewdatalist; } @override public myrecyclerviewadapter.viewholder oncreateviewholder(viewgroup parent, int viewtype) { layoutinflater inflater = layoutinflater.from(parent.getcontext()); view view = inflater.inflate(r.layout.item_recycler_view, parent, false); return new viewholder(view); } @override public void onbindviewholder(viewholder holder, int position) { holder.binddatawithviewholder(mrviewdatalist.get(position),position); } @override public int getitemcount() { return mrviewdatalist != null ? mrviewdatalist.size() : 0; } public class viewholder extends recyclerview.viewholder { private textview textview; private linearlayout llview; private datamodel mdataitem=null; public viewholder(view itemview) { super(itemview); llview=(linearlayout)itemview.findviewbyid(r.id.ll_root_view); textview = (textview) itemview.findviewbyid(r.id.tvitemname); cvitemview.setonclicklistener(new view.onclicklistener() { @override public void onclick(view v) { //handling background selection state changed int previousselectstate=mselecteditemposition; mselecteditemposition = getadapterposition(); //notify previous selected item notifyitemchanged(previousselectstate); //notify new selected item notifyitemchanged(mselecteditemposition); //your other handling in onclick } }); } //this clean method bind data viewholder. dirty things on view based on dataitem. //must called onbindviewholder(),with dataitem. in our case dataitem string object. public void binddatawithviewholder(datamodel dataitem, int currentposition){ this.mdataitem=dataitem; //handle selection state in object view. if(currentposition == mselecteditemposition){ llview.setbackgroundcolor(color.parsecolor(selcted_color); }else{ llview.setbackgroundcolor(color.parsecolor(default_color); } //other view binding logics setting text , loading image etc. textview.settext(mdataitem); } } }
if have maintain selected item state, discourage use of notifydatasetchanged() method of adapter class recyclerview provides more flexibility these cases.
Comments
Post a Comment