Android:具有多个可单击按钮的ListView元素

Android:具有多个可单击按钮的ListView元素,android,listview,button,Android,Listview,Button,我有一个列表视图,其中列表中的每个元素都包含一个文本视图和两个不同的按钮。大概是这样的: ListView -------------------- [Text] [Button 1][Button 2] -------------------- [Text] [Button 1][Button 2] -------------------- ... (and so on) ... 使用此代码,我可以为整个项目创建一个OnItemClickListener: listView.setOnIte

我有一个
列表视图
,其中列表中的每个元素都包含一个文本视图和两个不同的按钮。大概是这样的:

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);

        }

    }
});
这导致不再有可选择的列表项。但这无助于使嵌套按钮可选择


有人有想法吗?

解决这个问题的方法实际上比我想象的要简单。您只需在自定义适配器的
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);

这对我来说很好,我可以用触摸屏点击按钮,也可以用键盘聚焦点击,我不确定这是不是最好的方式,但效果很好,所有代码都保存在您的阵列适配器中

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;
}

}
包br.com.fontolan.pessoas.arrayadapter;
导入java.util.List;
导入android.content.Context;
导入android.text.Editable;
导入android.text.TextWatcher;
导入android.view.LayoutInflater;
导入android.view.view;
导入android.view.view.OnClickListener;
导入android.view.ViewGroup;
导入android.widget.ArrayAdapter;
导入android.widget.EditText;
导入android.widget.ImageView;
进口br.com.fontolan.pessoas.R;
导入br.com.fontolan.pessoas.model.Telefone;
公共类电话适配器扩展阵列适配器{
私人电话号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码号码;
私人语境;
私有EditText-tipoEditText=null;
私有编辑文本telefoneditext=null;
私有ImageView deleteImageView=null;
公用电话适配器(上下文、列表值){
super(上下文、R.layout.telefone_形式、值);
this.telefonarrayadapter=this;
this.context=上下文;
}
@凌驾
公共视图getView(int位置、视图转换视图、视图组父视图){
LayoutFlater充气器=(LayoutFlater)context.getSystemService(context.LAYOUT\u充气器\u服务);
视图=充气机。充气(R.layout.telefone_表单,父项,false);
tipoEditText=(EditText)view.findviewbyd(R.id.telefone\u form\u tipo);
telefoneEditText=(EditText)view.findViewById(R.id.telefone\u form\u telefone);
deleteImageView=(ImageView)view.findViewById(R.id.telefone\u form\u delete\u image);
最终int i=位置;
最终Telefone Telefone=此.getItem(位置);
tipoEditText.setText(telefone.getTipo());
telefoneditext.setText(telefone.getTelefone());
TextWatcher tipoTextWatcher=新的TextWatcher(){
@凌驾
public void onTextChanged(字符序列、int start、int before、int count){
}
@凌驾
更改前文本之前的公共void(字符序列s、int start、int count、int after){
}
@凌驾
公共无效后文本已更改(可编辑){
telefonarrayadapter.getItem(i).setTipo(s.toString());
telefonarrayadapter.getItem(i).setIsDirty(true);
}
};
TextWatcher telefoneTextWatcher=新的TextWatcher(){
@凌驾
public void onTextChanged(字符序列、int start、int before、int count){
}
@凌驾
更改前文本之前的公共void(字符序列s、int start、int count、int after){
}
@凌驾
公共无效后文本已更改(可编辑){
telefonarrayadapter.getItem(i).setTelefone(s.toString());
telefonarrayadapter.getItem(i).setIsDirty(true);
}
};
tipoEditText.addTextChangedListener(tipoTextWatcher);
telefoneEditText.addTextChangedListener(telefoneTextWatcher);
deleteImageView.setOnClickListener(新的OnClickListener(){
@凌驾
公共void onClick(视图v){
telefone适配器。移除(telefone);
}
});
返回视图;
}
}

此实现的平台解决方案不是使用长按显示的上下文菜单吗

问题作者是否知道上下文菜单?在listview中堆叠按钮会影响性能,会使UI混乱,并违反平台的推荐UI设计

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

这本指南应该给你一个良好的开端


与上述用户相比,我没有太多经验,但我遇到了同样的问题,我用下面的解决方案解决了这个问题

<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"
        />

我知道已经晚了,但这可能会有所帮助,这是我如何为不同的单击操作编写自定义适配器类的一个示例

 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;
    }
}

仍然需要这些吗?如果您查看BaseAdapter代码,您会看到areAllItemsEnabled()和isEnabled()只是硬编码为true,使它们成为没有任何逻辑的简单占位符。如果我想使用SimpleCrsorAdapter怎么办?我必须使自定义适配器扩展SimpleCrsorAdapter吗?已修复。感谢您的报道:-)您从查询中获得curItem.url的详细程度如何,您能更具体一点吗?谢谢znq,这对我非常有用。。。节省了大量时间。在11:39观看这个演讲有一个很好的例子:然后在convertView==null时按@znq所说的做…setTag(),并在onClick中执行getTag()(
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;
    }
}