Android: 带有多个可点击按钮的 ListView 元素

我有一个 ListView,其中列表中的每个元素都包含一个 TextView 和两个不同的按钮:

ListView
--------------------
[Text]
[Button 1][Button 2]
--------------------
[Text]
[Button 1][Button 2]
--------------------
... (and so on) ...

通过这段代码,我可以为整个项目创建一个 OnItemClickListener:

listView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> list, View view, int position, long id) {
Log.i(TAG, "onListItemClick: " + position);


}


}
});

但是,我不希望整个项目是可点击的,而只是每个列表元素的两个按钮。

因此,我的问题是,如何用以下参数为这两个按钮实现 onClickListener:

  • int button(已单击元素的哪个按钮)
  • int position(这是按钮单击发生的列表中的元素)

更新: 我找到了一个解决方案,就像我在下面的回答中描述的那样。现在我可以通过触摸屏点击/点击按钮。但是,我不能用轨迹球手动选择它。它总是选择整个列表项,然后直接进入下一个列表项,忽略按钮,即使我为 getView()中的按钮设置了 .setFocusable(true)setClickable(true)

我还将这段代码添加到我的自定义列表适配器:

@Override
public boolean  areAllItemsEnabled() {
return false;
}


@Override
public boolean isEnabled(int position) {
return false;
}

这导致根本不再有任何列表项可选。但是它没有帮助使嵌套按钮可选。

有人知道吗?

222056 次浏览

解决这个问题其实比我想象的要容易。您可以简单地在自定义适配器的 getView()方法中为您正在使用的按钮添加 setOnClickListener ()。

任何与按钮相关的数据都必须与 getView()中的 myButton.setTag()一起添加,并且可以通过 view.getTag()在 onClickListener 中访问

作为一个教程,我在 我的博客上发布了一个详细的解决方案。

也许你已经知道怎么做了,但是你可以打电话

ListView.setItemsCanFocus(true)

现在你的扣子会抓住焦点

这就是@znq 的回答。

在许多情况下,您希望知道单击项的行位置,并希望知道该行中的哪个视图被点击。这在平板电脑 UI 中将会更加重要。

您可以使用以下自定义适配器完成此操作:

private static class CustomCursorAdapter extends CursorAdapter {


protected ListView mListView;


protected static class RowViewHolder {
public TextView mTitle;
public TextView mText;
}


public CustomCursorAdapter(Activity activity) {
super();
mListView = activity.getListView();
}


@Override
public void bindView(View view, Context context, Cursor cursor) {
// do what you need to do
}


@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View view = View.inflate(context, R.layout.row_layout, null);


RowViewHolder holder = new RowViewHolder();
holder.mTitle = (TextView) view.findViewById(R.id.Title);
holder.mText = (TextView) view.findViewById(R.id.Text);


holder.mTitle.setOnClickListener(mOnTitleClickListener);
holder.mText.setOnClickListener(mOnTextClickListener);


view.setTag(holder);


return view;
}


private OnClickListener mOnTitleClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
final int position = mListView.getPositionForView((View) v.getParent());
Log.v(TAG, "Title clicked, row %d", position);
}
};


private OnClickListener mOnTextClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
final int position = mListView.getPositionForView((View) v.getParent());
Log.v(TAG, "Text clicked, row %d", position);
}
};
}

对于未来的读者:

使用轨迹球手动选择按钮:

myListView.setItemsCanFocus(true);

并禁用对整个列表项的焦点:

myListView.setFocusable(false);
myListView.setFocusableInTouchMode(false);
myListView.setClickable(false);

它对我来说很好用,我可以用触摸屏点击按钮,也可以用键盘对焦点击

我不确定这是否是最好的方法,但是可以正常工作,所有代码都保留在 ArrayAdapter 中。

package br.com.fontolan.pessoas.arrayadapter;


import java.util.List;


import android.content.Context;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import br.com.fontolan.pessoas.R;
import br.com.fontolan.pessoas.model.Telefone;


public class TelefoneArrayAdapter extends ArrayAdapter<Telefone> {


private TelefoneArrayAdapter telefoneArrayAdapter = null;
private Context context;
private EditText tipoEditText = null;
private EditText telefoneEditText = null;
private ImageView deleteImageView = null;


public TelefoneArrayAdapter(Context context, List<Telefone> values) {
super(context, R.layout.telefone_form, values);
this.telefoneArrayAdapter = this;
this.context = context;
}


@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.telefone_form, parent, false);


tipoEditText = (EditText) view.findViewById(R.id.telefone_form_tipo);
telefoneEditText = (EditText) view.findViewById(R.id.telefone_form_telefone);
deleteImageView = (ImageView) view.findViewById(R.id.telefone_form_delete_image);


final int i = position;
final Telefone telefone = this.getItem(position);
tipoEditText.setText(telefone.getTipo());
telefoneEditText.setText(telefone.getTelefone());


TextWatcher tipoTextWatcher = new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}


@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}


@Override
public void afterTextChanged(Editable s) {
telefoneArrayAdapter.getItem(i).setTipo(s.toString());
telefoneArrayAdapter.getItem(i).setIsDirty(true);
}
};


TextWatcher telefoneTextWatcher = new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}


@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}


@Override
public void afterTextChanged(Editable s) {
telefoneArrayAdapter.getItem(i).setTelefone(s.toString());
telefoneArrayAdapter.getItem(i).setIsDirty(true);
}
};


tipoEditText.addTextChangedListener(tipoTextWatcher);
telefoneEditText.addTextChangedListener(telefoneTextWatcher);


deleteImageView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
telefoneArrayAdapter.remove(telefone);
}
});


return view;
}


}

这个实现的平台解决方案不是使用一个在长按中显示的上下文菜单吗?

问题作者是否知道上下文菜单?在列表视图中堆叠按钮具有性能影响,将使用户界面混乱,并违反平台的推荐用户界面设计。

另一方面,上下文菜单——本质上没有被动表示——对最终用户来说并不明显。考虑记录这种行为?

这本指南会给你一个良好的开端。

Http://www.mikeplate.com/2010/01/21/show-a-context-menu-for-long-clicks-in-an-android-listview/

我没有多少经验比上面的用户,但我面临着同样的问题,我解决了下面的解决方案

<Button
android:id="@+id/btnRemove"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/btnEdit"
android:layout_weight="1"
android:background="@drawable/btn"
android:text="@string/remove"
android:onClick="btnRemoveClick"
/>

BtnRemoveClick 事件

public void btnRemoveClick(View v)
{
final int position = listviewItem.getPositionForView((View) v.getParent());
listItem.remove(position);
ItemAdapter.notifyDataSetChanged();


}

我知道这是晚了,但这可能会有帮助,这是一个例子,我如何编写自定义适配器类为不同的点击动作

 public class CustomAdapter extends BaseAdapter {


TextView title;
Button button1,button2;


public long getItemId(int position) {
return position;
}


public int getCount() {
return mAlBasicItemsnav.size();  // size of your list array
}


public Object getItem(int position) {
return position;
}


public View getView(int position, View convertView, ViewGroup parent) {


if (convertView == null) {
convertView = getLayoutInflater().inflate(R.layout.listnavsub_layout, null, false); // use sublayout which you want to inflate in your each list item
}


title = (TextView) convertView.findViewById(R.id.textViewnav); // see you have to find id by using convertView.findViewById
title.setText(mAlBasicItemsnav.get(position));
button1=(Button) convertView.findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//your click action


// if you have different click action at different positions then
if(position==0)
{
//click action of 1st list item on button click
}
if(position==1)
{
//click action of 2st list item on button click
}
});


// similarly for button 2


button2=(Button) convertView.findViewById(R.id.button2);
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//your click action


});






return convertView;
}
}