java - ListView row buttons: How do I create a custom Adapter that connects a View.OnClickListener to a button on each row of a ListView? -


i want listview contain buttons, setting button's xml property, onclick="myfunction" , placing public void myfunction(android.view.view view) method in activity causes nosuchmethodexception (the stack trace null) thrown, although onclick listener there, doesn't fire myfunction(...) , cause activity close.

how create custom adapter connects view.onclicklistener button on each row of listview?

my listview created follows...

[activity.java content..]

public void myfunction(android.view.view view) {     //do stuff } 

[activity.xml content..]

<linearlayout xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".frmcustomerdetails" >     <listview android:id="@+id/lstcustomerdetailslist" android:layout_width="fill_parent" android:layout_height="0dip" android:layout_weight="1" android:clickable="true" android:clipchildren="true" android:divider="@null" android:dividerheight="0dp" android:fastscrollenabled="true" android:footerdividersenabled="false" android:headerdividersenabled="false" android:requiresfadingedge="vertical" android:smoothscrollbar="true" /> </linearlayout> 

[activity_row_item.xml content..]

<?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:id="@+id/llt" android:layout_width="match_parent" android:layout_height="match_parent" >     <button android:id="@+id/btn" android:text="click me" android:onclick="myfunction" /> </linearlayout> 

here how create custom adapter, connecting view.onclicklistener listview button per row...

1. create layout typical row

in case, row composed of 3 view components:

  • name (edittext)
  • value (edittext:inputtype="numberdecimal")
  • delete (button)

xml

pay_list_item.xml layout follows:

<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android"     android:layout_width="fill_parent"     android:layout_height="fill_parent" >      <edittext         android:id="@+id/pay_name"         android:layout_width="0dp"         android:layout_height="fill_parent"         android:layout_weight="2"         android:hint="name" />      <edittext         android:id="@+id/pay_value"         android:layout_width="0dp"         android:layout_height="fill_parent"         android:layout_weight="1"         android:inputtype="numberdecimal"         android:text="0.0" />      <button         android:id="@+id/pay_removepay"         android:layout_width="100dp"         android:layout_height="fill_parent"         android:text="remove pay"         android:onclick="removepayonclickhandler" />  </linearlayout> 

note: button has onclick handler defined in xml layout file, because want refer action specific list item.

doing means handler implemented in activity file , each button know list item belongs to.

2. create list item adapter

this java class controller pay_list_item.xml.

it keeps references of views, , puts these references in tags, extending arrayadapter interface.

the adapter:

public class paylistadapter extends arrayadapter<payment> {      private list<payment> items;     private int layoutresourceid;     private context context;      public paylistadapter(context context, int layoutresourceid, list<payment> items) {         super(context, layoutresourceid, items);         this.layoutresourceid = layoutresourceid;         this.context = context;         this.items = items;     }      @override     public view getview(int position, view convertview, viewgroup parent) {         view row = convertview;         paymentholder holder = null;          layoutinflater inflater = ((activity) context).getlayoutinflater();         row = inflater.inflate(layoutresourceid, parent, false);          holder = new paymentholder();         holder.payment = items.get(position);         holder.removepaymentbutton = (imagebutton)row.findviewbyid(r.id.pay_removepay);         holder.removepaymentbutton.settag(holder.payment);          holder.name = (textview)row.findviewbyid(r.id.pay_name);         holder.value = (textview)row.findviewbyid(r.id.pay_value);          row.settag(holder);          setupitem(holder);         return row;     }      private void setupitem(paymentholder holder) {         holder.name.settext(holder.payment.getname());         holder.value.settext(string.valueof(holder.payment.getvalue()));     }      public static class paymentholder {         payment payment;         textview name;         textview value;         imagebutton removepaymentbutton;     } } 

here list payment class items.

there 3 important elements here:

  • paylistadapter constructor: sets private fields , calls superclass constructor. gets list of payment objects. implementation obligatory.
  • paymentholder: static class holds references views have set in list item. keep payment object references particular item in list. set tag imagebutton, me find payment item on list, user wanted remove
  • overriden getview method: called superclass. goal return single list row. create fields , setup values , store them in static holder. holder put in row’s tag element. note there performance issue, row being recreated each time displayed. used add flag in holder iscreated, , set true after row created. can add if statement , read tag’s holder instead of creating scratch.

payment.java quite simple , looks bit basicnamevaluepair:

public class payment implements serializable {     private string name = "";     private double value = 0;      public payment(string name, double value) {         this.setname(name);         this.setvalue(value);     } ... } 

there additional gets , sets each private field not shown.

3. add listview activity layout xml file

in simpliest form, enough add view activity layout:

<listview      android:id="@+id/enterpays_payslist"     android:layout_width="fill_parent"     android:layout_height="wrap_content"> </listview> 

4. set adapter list view in activity java code

in order display items in listview need set adapter , map other arraylist of payment objects (as extending array adapter here). here code responsible binding adapter editpersondata.getpayments() arraylist:

paylistadapter adapter = new paylistadapter(addnewperson.this, r.layout.pay_list_item, editpersondata.getpayments()); listview payslistview = (listview)findviewbyid(r.id.enterpays_payslist); payslistview.setadapter(adapter); 

5. adding / removing items listview (and adapter)

adapter handled other arraylist, adding new element simple as:

payment testpayment = new payment("test", 13); adapter.add(testpayment); adapter.remove(testpayment); 

6. handle remove payment button click event

in activity’s code, listview displayed, add public method handle remove button click action. method name has same in pay_list_item.xml:

android:onclick="removepayonclickhandler" method body follows:  public void removepayonclickhandler(view v) {     payment itemtoremove = (payment)v.gettag();     adapter.remove(itemtoremove); } 

the payment object stored in imagebutton’s tag element. enough read tag, , remove item adapter.

7. incorporate remove confirmation dialog window

probably need make sure user intentionally pressed remove button asking him additional question in confirmation dialog.

dialogue

a) create dialog’s id constant

this dialog’s id. should unique among other dialog window handled current activity. set that:

protected static final int dialog_remove_calc = 1; protected static final int dialog_remove_person = 2; 

b) build dialog

i use method build dialog window:

private dialog createdialogremoveconfirm(final int dialogremove) {     return new alertdialog.builder(getapplicationcontext())     .seticon(r.drawable.trashbin_icon)     .settitle(r.string.calculation_dialog_remove_text)     .setpositivebutton(r.string.calculation_dialog_button_ok, new dialoginterface.onclicklistener() {         public void onclick(dialoginterface dialog, int whichbutton) {             handleremoveconfirm(dialogremove);         }     })     .setnegativebutton(r.string.calculation_dialog_button_cancel, null)     .create(); } 

alertdialog builder pattern utilized here. not handle negativebutton click action – default dialog being hidden. if dialog’s confirm button clicked, handleremoveconfirm callback called , action performed based on dialog’s id:

protected void handleremoveconfirm(int dialogtype) {     if(dialogtype == dialog_remove_person){         calc.removeperson();     }else if(dialogtype == dialog_remove_calc){         removecalc();     } } 

c) show dialog

i show dialog after remove button click. showdialog(int) android’s activity’s method:

onclicklistener removecalcbuttonclicklistener = new onclicklistener() {     public void onclick(view v) {         showdialog(dialog_remove_calc);     } }; 

the showdialog(int) method calls oncreatedialog (also defined in activity’s class). override , tell app if showdialog requested:

@override protected dialog oncreatedialog(int id) {     switch (id) {     case dialog_remove_calc:         return createdialogremoveconfirm(dialog_remove_calc);     case dialog_remove_person:         return createdialogremoveconfirm(dialog_remove_person);     } } 

Comments

Popular posts from this blog

Why does Ruby on Rails generate add a blank line to the end of a file? -

keyboard - Smiles and long press feature in Android -

node.js - Bad Request - node js ajax post -