ListView中排按钮:我如何创建在一个ListView的每一行View.OnClickListener连接到一个按钮自定义适配器? [英] ListView row buttons: How do I create a custom Adapter that connects a View.OnClickListener to a button on each row of a ListView?

查看:339
本文介绍了ListView中排按钮:我如何创建在一个ListView的每一行View.OnClickListener连接到一个按钮自定义适配器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望我的ListView包含按钮,但在活动设置按钮的XML属性的onClick =myFunction的,然后把一个公共无效myFunction的(android.view.View视图)方法会导致NoSuchMethodException(堆栈跟踪是空)被抛出,因为虽然onClick的监听器那里,它不火myFunction的(...),并导致活动关闭。

我如何创建在一个ListView的每一行?

一个View.OnClickListener连接到一个按钮自定义适配器

创建我的ListView控件如下...

[activity.java内容...]

 公共无效myFunction的(android.view.View视图)
{
    //做的东西
}

[activity.xml内容...]

 < LinearLayout中的xmlns:工具=htt​​p://schemas.android.com/tool​​s的xmlns:机器人=htt​​p://schemas.android.com/apk/res / Android的机器人:layout_width =match_parent机器人:layout_height =match_parent机器人:方向=垂直工具:上下文=。FrmCustomerDetails>
    < ListView的机器人:ID =@ + ID / LstCustomerDetailsList的android:layout_width =FILL_PARENT机器人:layout_height =0dip机器人:layout_weight =1机器人:可点击=真正的机器人:clipChildren =真正的机器人:分=@空机器人:dividerHeight =0dp机器人:fastScrollEnabled =真正的机器人:footerDividersEnabled =false的机器人:headerDividersEnabled =false的机器人:requiresFadingEdge =垂直机器人:smoothScrollbar =真/ >
< / LinearLayout中>

[activity_row_item.xml内容...]

 <?XML版本=1.0编码=UTF-8&GT?;
< LinearLayout中的xmlns:机器人=htt​​p://schemas.android.com/apk/res/android的xmlns:工具=htt​​p://schemas.android.com/tool​​s机器人:ID =@ + ID / LLT的android:layout_width =match_parent机器人:layout_height =match_parent>
    <按钮机器人:ID =@ + ID / BTN机器人:文本=点击我机器人:的onClick =myFunction的/>
< / LinearLayout中>


解决方案

下面是如何创建自定义适配器,连接View.OnClickListener到ListView每行一个按钮...

1)首先,我们必须为一个典型的行创建布局

在这种情况下,该行是由三个视图组件的


  • 域名(EditText上)

  • 值(EditText上:inputType下=numberDecimal)

  • 删除(按钮)

pay_list_item.xml布局如下:

 <?XML版本=1.0编码=UTF-8&GT?;
< LinearLayout中的xmlns:机器人=htt​​p://schemas.android.com/apk/res/android
    机器人:layout_width =FILL_PARENT
    机器人:layout_height =FILL_PARENT>    <的EditText
        机器人:ID =@ + ID / pay_name
        机器人:layout_width =0dp
        机器人:layout_height =FILL_PARENT
        机器人:layout_weight =2
        机器人:提示=名称/>    <的EditText
        机器人:ID =@ + ID / pay_value
        机器人:layout_width =0dp
        机器人:layout_height =FILL_PARENT
        机器人:layout_weight =1
        安卓的inputType =numberDecimal
        机器人:文本=0.0/>    <按钮
        机器人:ID =@ + ID / pay_removePay
        机器人:layout_width =100dp
        机器人:layout_height =FILL_PARENT
        机器人:文字=删除买单
        安卓的onClick =removePayOnClickHandler/>< / LinearLayout中>

请注意,此按钮已在XML布局文件中的onClick处理函数定义。

这是因为我们要参考其作用于特定列表项。

否则这意味着该处理程序将在活动文件来实现,并且每个按钮将知道它所属的列表项。

2)创建列表项适配器

这是java类,它是pay_list_item.xml控制器。

它保持引用其所有的意见,而且也使这些引用的标签,扩展一个ArrayAdapter接口。

该适配器:

 公共类PayListAdapter扩展ArrayAdapter<付款和GT; {    私人列表<付款和GT;项目;
    私人诠释layoutResourceId;
    私人上下文的背景下;    公共PayListAdapter(上下文的背景下,诠释layoutResourceId,列表与LT;付款和GT;项目){
        超(背景下,layoutResourceId,项目);
        this.layoutResourceId = layoutResourceId;
        this.context =背景;
        this.items =物品;
    }    @覆盖
    公共查看getView(INT位置,查看convertView,父母的ViewGroup){
        查看排= convertView;
        PaymentHolder支架=无效;        LayoutInflater充气=((活动)上下文).getLayoutInflater();
        行= inflater.inflate(layoutResourceId,父母,假);        持有人=新PaymentHolder();
        holder.Payment = items.get(位置);
        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(保持器);        setupItem(保持器);
        返回行;
    }    私人无效setupItem(PaymentHolder持有人){
        holder.name.setText(holder.Payment.getName());
        holder.value.setText(将String.valueOf(holder.Payment.getValue()));
    }    公共静态类PaymentHolder {
        付款方式付款方式;
        TextView的名称;
        TextView的价值;
        的ImageButton removePaymentButton;
    }
}

下面我们列出了支付类项目。

在这里有三个最重要的元素:


  • PayListAdapter构造:设置一些私人领域,并调用父类的构造。这也得到付款对象的名单。它的实施是强制性的。

  • PaymentHolder:保存到我在这个列表项来设置所有视图引用静态类。我还留着支付对象,在此列表中特定项目的引用。我将它作为标签的ImageButton的,这将有助于我找到名单上的付款项,该用户想要删除

  • 重写getView方法:由超类。它的目标是返回一个列表行。我们创造的领域和设置它们的值并将其存储在静态持有。持有人则是放在行的标签元素。注意,存在性能问题,因为该行每次被显示的时间被重新创建。我用添加一些标志像isCreated持有人,并将其设置为true一行已经创建后。然后你可以添加if语句,读,而不是从头开始创建该标签的持有人。

Payment.java是现在很简单,它看起来有点像BasicNameValuePair:

 公共类支付实现Serializable {
    私人字符串名称=;
    私人双人值= 0;    公共支付(字符串名称,双击值){
        this.setName(名);
        this.setValue(值);
    }
...
}

有更多的获取并设置每个私有字段不显示。

3)添加ListView控件在活动布局xml文件

在simpliest形式,它是足够的这一观点加入到活动布局:

 < ListView控件
    机器人:ID =@ + ID / EnterPays_PaysList
    机器人:layout_width =FILL_PARENT
    机器人:layout_height =WRAP_CONTENT>
< /&的ListView GT;

4)设置适配器在活动的Java code此列表视图

为了显示在ListView控件,你需要设置它的适配器,并将其映射到支付对象的某些其他的ArrayList(因为我在这里延伸的阵列适配器)项目。这里是code,负责结合适配器editPersonData.getPayments()的ArrayList

  PayListAdapter适配器=新PayListAdapter(AddNewPerson.this,R.layout.pay_list_item,editPersonData.getPayments());
ListView控件PaysListView =(ListView控件)findViewById(R.id.EnterPays_PaysList);
PaysListView.setAdapter(适配器);

5)添加/删除项目的ListView(和它的适配器)

适配器的处理就像任何其他的ArrayList,因此增加新的元素是简单:

 付款testPayment =新的付款方式(测试,13);
adapter.add(testPayment);
adapter.remove(testPayment);

6)处理移除付款按钮点击事件

在一个活动的code,其中显示的ListView,添加将处理删除按钮单击动作公共方法。该方法的名称必须是因为它是在pay_list_item.xml完全相同的:

 安卓的onClick =removePayOnClickHandler
方法体如下:公共无效removePayOnClickHandler(视图v){
    付款itemToRemove =(支付)v.getTag();
    adapter.remove(itemToRemove);
}

支付对象存储在的ImageButton的标签元素。现在,它足以从标签读取它,从适配器删除该项目。

7)把删除确认对话框窗口

也许你也需要确保用户故意$ P $问他在确认对话框另一个问题pssed删除按钮。

对话

1)创建对话框的ID常量

这简直是对话框的ID。它应该是受当前活动处理的任何其他对话窗口中是唯一的。我将它设置这样的:

 受保护的静态最终诠释DIALOG_REMOVE_CALC = 1;
受保护的静态最终诠释DIALOG_REMOVE_PERSON = 2;

2)建立对话

我用这个方法来构建对话窗口:

 私人对话createDialogRemoveConfirm(最终诠释dialogRemove){
    返回新AlertDialog.Builder(getApplicationContext())
    .setIcon(R.drawable.trashbin_icon)
    .setTitle(R.string.calculation_dialog_remove_text)
    .setPositiveButton(R.string.calculation_dialog_button_ok,新DialogInterface.OnClickListener(){
        公共无效的onClick(DialogInterface对话,诠释whichButton){
            handleRemoveConfirm(dialogRemove);
        }
    })
    .setNegativeButton(R.string.calculation_dialog_button_cancel,NULL)
    。创建();
}

AlertDialog生成器模式在这里利用。我不处理NegativeButton单击动作 - 默认情况下,对话只是被隐藏。如果点击对话框中的确认键,我handleRemoveConfirm回调被调用和行动是基于对话框的ID来执行:

 保护无效handleRemoveConfirm(INT的DialogType){
    IF(==的DialogType DIALOG_REMOVE_PERSON){
        calc.removePerson();
    }否则如果(==的DialogType DIALOG_REMOVE_CALC){
        removeCalc();
    }
}

3)显示对话框

我告诉我的删除按钮后点击对话框。 ShowDialog的(INT)是Android的活动的方式:

  OnClickListener removeCalcButtonClickListener =新OnClickListener(){
    公共无效的onClick(视图v){
        的ShowDialog(DIALOG_REMOVE_CALC);
    }
};

ShowDialog的(int)方法调用onCreateDialog(在活动的类定义)。覆盖它,并告诉你的应用程序如果请求调用ShowDialog做什么:

  @覆盖
保护对话框onCreateDialog(INT ID){
    开关(ID){
    案例DIALOG_REMOVE_CALC:
        返回createDialogRemoveConfirm(DIALOG_REMOVE_CALC);
    案例DIALOG_REMOVE_PERSON:
        返回createDialogRemoveConfirm(DIALOG_REMOVE_PERSON);
    }
}

I want my ListView to contain buttons, but setting the button's xml property, onClick="myFunction" and then placing a public void myFunction(android.view.View view) method in the activity causes an NoSuchMethodException (the stack trace is null) to be thrown, as although the onclick listener is there, it doesn't fire myFunction(...) and cause the activity to close.

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

My ListView is created as 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 is how to create the custom Adapter, connecting View.OnClickListener to a ListView with a button per row...

1) First, we must create a layout for a typical row

In this case, the row is composed of three view components:

  • name (EditText)
  • value (EditText:inputType="numberDecimal")
  • delete (Button)

pay_list_item.xml layout is as 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>

Notice, that the button has onClick handler defined in xml layout file.

This is because we want to refer its action to a specific list item.

Doing this means that the handler will be implemented in Activity file and each button will know which list item it belongs to.

2) Create list item adapter

This is the java class that is the controller for pay_list_item.xml.

It keeps references for all of its views, and it also puts these references in tags, extending the 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 we list the Payment class items.

There are three most important elements here:

  • PayListAdapter constructor: sets some private fields and calls superclass constructor. It also gets the List of Payment objects. Its implementation is obligatory.
  • PaymentHolder: static class that holds references to all views that I have to set in this list item. I also keep the Payment object that references to this particular item in list. I set it as tag for ImageButton, that will help me to find the Payment item on list, that user wanted to remove
  • Overriden getView method: called by superclass. Its goal is to return the single List row. We create its fields and setup their values and store them in static holder. Holder then is put in row’s tag element. Note that there is a performance issue, as the row is being recreated each time it is displayed. I used to add some flag in holder like isCreated, and set it to true after row was already created. then you can add if statement and read tag’s holder instead of creating it from scratch.

Payment.java is quite simple as for now and it looks a bit like 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 are additional gets and sets for each private field not shown.

3) Add ListView in your activity layout xml file

In the simpliest form, it is enough to add this view to activity layout:

<ListView 
    android:id="@+id/EnterPays_PaysList"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content">
</ListView>

4) Set up adapter to this list view in Activity Java code

In order to display items in ListView you need to set up its adapter and map it to some other ArrayList of Payment objects (as I am extending an Array adapter here). Here is code that is responsible for binding adapter to 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 to ListView (and its adapter)

Adapter is handled just like any other ArrayList, so adding new element to it is as simple as:

Payment testPayment = new Payment("Test", 13);
adapter.add(testPayment);
adapter.remove(testPayment);

6) Handle Remove Payment button click event

In an activity’s code, where ListView is displayed, add public method that will handle remove button click action. The method name has to be exactly the same as it was in pay_list_item.xml:

android:onClick="removePayOnClickHandler"
The method body is as follows:

public void removePayOnClickHandler(View v) {
    Payment itemToRemove = (Payment)v.getTag();
    adapter.remove(itemToRemove);
}

The Payment object was stored in ImageButton’s Tag element. Now it is enough to read it from Tag, and remove this item from the adapter.

7) Incorporate remove confirmation dialog window

Probably you need also make sure that user intentionally pressed the remove button by asking him additional question in confirmation dialog.

Dialogue

1) Create dialog’s id constant

This is simply dialog’s ID. it should be unique among any other dialog window that is handled by current activity. I set it like that:

protected static final int DIALOG_REMOVE_CALC = 1;
protected static final int DIALOG_REMOVE_PERSON = 2;

2) Build dialog

I use this method to 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 is utilized here. I do not handle NegativeButton click action – by default the dialog is just being hidden. If dialog’s confirm button is clicked, my handleRemoveConfirm callback is called and action is 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();
    }
}

3) Show Dialog

I show dialog after my remove button click. The showDialog(int) is 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 it and tell your app what to do if the showDialog was 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);
    }
}

这篇关于ListView中排按钮:我如何创建在一个ListView的每一行View.OnClickListener连接到一个按钮自定义适配器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆