ListView setOnItemClickListener no funciona al agregar el botón

89

Tengo una vista de lista con texto y botón en cada fila, la vista de lista setOnItemClickListener () no funciona. ¿Es posible manejar eventos de clic de elemento y clic de botón de manera diferente (el clic de elemento debe llamar a ActivityA y el clic de botón debe llamar a ActivityB)? Alguien tiene una solución

    private ArrayList<String> userIDArr = null;
    private ArrayList<String> userNameArr = null;
    private DatabaseHelper dbHelper = null;
    private ListView userListView=null; 


    public void onCreate(Bundle savedInstanceState) 
        {
          super.onCreate(savedInstanceState);         
          setContentView(R.layout.list_view);         
          dbHelper = new DatabaseHelper(this.getApplicationContext());        
          Map<String,ArrayList<String>> displayMap = dbHelper.getUserListToDisplay();
          userIDArr = displayMap.get("UserID");
          userNameArr = displayMap.get("FirstName1");           


          userListView = (ListView) findViewById(R.id.listView2);
          userListView.setAdapter(new UserListAdapter(this,userIDArr));


          userListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
              @Override
              public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) {

                  Toast.makeText(usersListActivity.this,
                            "Item in position " + position + " clicked", Toast.LENGTH_LONG).show();
              }
            });
     }


    public class UserListAdapter extends ArrayAdapter<String>
    {
        Activity context;
        public UserListAdapter(Activity context, ArrayList<String> names) {
            super(context, R.layout.list_item, names);
            this.context = context;
        }
        private class ViewHolder {
            public TextView UserNameAndID;
            public TextView Description;
            public Button  UploadBtn;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder;
            View rowView = convertView;
            if (rowView == null) {
                LayoutInflater inflater = context.getLayoutInflater();
                rowView = inflater.inflate(R.layout.list_item, null, true);
                holder = new ViewHolder();
                holder.UserNameAndID = (TextView) rowView.findViewById(R.id.User_detailsTxt);
                holder.Description = (TextView) rowView.findViewById(R.id.User_status);
                holder.UploadBtn = (Button) rowView.findViewById(R.id.uploadbutton);
                holder.UploadBtn.setOnClickListener(new View.OnClickListener() {  

                        public void onClick(View v) {  
                        Toast.makeText(usersListActivity.this," Button clicked",Toast.LENGTH_SHORT).show();
                        }   
                    }); 
                    rowView.setTag(holder);
            } else {
                holder = (ViewHolder) rowView.getTag();
            }
            String s = userNameArr.get(position)+","+userIDArr.get(position);
            holder.UserNameAndID.setText(s);
            holder.Description.setText("U r in middle");
            return rowView;
        }
    }
}`
Kishore
fuente

Respuestas:

260

Intente configurar sus botones (o cualquier otra vista que desee manejar, haga clic dentro de un elemento de la lista) de esta manera:

android:focusable="false"
android:focusableInTouchMode="false"
Ben Lee
fuente
@Ben Lee: ¡Los agregué a mis casillas de verificación! Sigue sin funcionar. ¿Qué puedo estar haciendo mal?
TDaver
1
android:focusableInTouchMode="false"resuelve el mío. Utilizo dos TextView en una fila LinearLayout personalizada. Yuk android ...
Youngjae
12
ImageButton no funcionará. En la vista de elementos de la lista contiene ImageButton, configure android: descendantFocusability = "blocksDescendants".
ChangUZ
8
también puede ser necesario agregar android: clickable = "false" (actívelo y desactívelo en el diseñador de diseño para que se agregue explícitamente al XML)
jrg
11
Advertencia: en caso de que esté utilizando un ImageButton, debe usar setFocusable (falso) porque el constructor de ImageButton habilitaría este atributo después de inflar desde el archivo xml. Pero buena respuesta sin embargo
Mateu
118

A veces, la lista aún no podrá hacer que el escucha de clics pase. Y en este caso, es posible que deba agregar un atributo más.

android:descendantFocusability="blocksDescendants" 

Y este atributo debe agregarse al diseño más superior de su XML donde ha proporcionado los elementos ListView.

Andro Selva
fuente
Solo para que nadie más haga lo que acabo de hacer: esto no será deseable si tiene algo que requiere enfoque en su fila como un EditText. Me siento estúpido ahora.
Kitalda
En mi caso este consejo me ha ayudado. Tengo un TextView y RadioButton, el primero no había hecho clic, el segundo no había seleccionado TextView. Escribí "android: clickable =" false "" en RadioButton.
CoolMind
Esta es la solución cuando el botón es un ImageButton
Mahonster
15

Si tiene una vista activa / vista enfocable en su vista de lista, entonces se desactivará onItemClickListener... puede intentar hacerla desenfocada agregando: android:focusable="false"a cualquier vista que generalmente sea enfocable.

nilesh
fuente
8

Lo del rebozado es añadirlo tanto Listeneral conjunto rowViewcomo al Buttoninterior Adapter. Algo como esto.

public class MyAdapter extends BaseAdapter implements View.OnClickListener{

    @Override
    public View getView(int position, View convertView, ViewGroup parent)
    {
            View rowView = convertView;
            if(rowView == null)
            {
                    //intialize rowView, and set onclick listener only once.
                    rowView = someIntilizationMehhodOrInflatorMethod();
                    //add listener to the button also and also to the row view
                    rowView.setOnClickListener(this);
            }
            //all your inflation and setting values goes here and at the end,
            //set position as tag to get the correct position, rather buggy one.
            rowView.setTag(String.valueOf(position));


            return rowView;
    }
    public void onClick(View v)
    {
            //now get the tag of View v and convert it to integer.
            int pos = Integer.parseInt(v.getTag().toString());
            Toast.makeText(context,"Item in position " + pos + " clicked",Toast.LENGTH_LONG).show();
    }
}
Adil Soomro
fuente
3
¿Cómo es esto incluso remotamente mejor? Está creando un onClickListener para CADA elemento de datos frente a solo 1 oyente. Tu ejemplo ni siquiera recicla qué vistas.
JRomero
@ J.Romero esto fue solo un ejemplo, aunque hay mucho espacio para la optimización del código. Sin embargo, acabo de actualizar el código.
Adil Soomro
5

Trate de establecer setClickable(false)para cada uno Button, ImageButton, etc, y Viewde esta manera:

view.setClickable(false);
button.setClickable(false);
imagebutton.setClickable(false);

También tienes que agregar

android:descendantFocusability="blocksDescendants"

al diseño principal (primer nivel)

Vlad
fuente
2
He descubierto que establecer bloques Descendientes es suficiente, no es necesario cancelar el enfoque, etc. Android 4.1
djdance
2

En lugar de agregar un botón, agregue ImageViewy proporcione un setOnItemClcikoyente que funcionaría bien.

public View getView(final int position, View convertView, ViewGroup parent) {
     MyViewHolder mViewHolder;
     if(convertView == null) {
         convertView = inflater.inflate(R.layout.youtubesearchrow, null);
         mViewHolder = new MyViewHolder();
         mViewHolder.alarm = (ImageView)convertView.findViewById(R.id.alarm);
         convertView.setTag(mViewHolder);
     } else {
         mViewHolder = (MyViewHolder) convertView.getTag();
     }

     mViewHolder.tvTitle = detail(convertView, R.id.tvTitle,    
     // mViewHolder.tvDesc  = detail(convertView, R.id.tvDesc,  
     mViewHolder.ivIcon  = detail_image(convertView, R.id.ivIcon,  

     mViewHolder.alarm.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
        // TODO Auto-generated method stub
        }
    });

        return convertView;
}
sharath yadhav
fuente
1

También recibo el mismo error. Si en la lista de distribución que tiene cualquier botón para sustituirlo por TextViewejemplo ImageButtoncon ImageView. Para referencia, su es mi código:

private Activity activity;
private LayoutInflater inflater;

private List<ItemList> itemListsItems;

private Bookmark_SharedPref pref;

ImageLoader imageLoader = AppController.getInstance().getImageLoader();

public CustomListAdapter_Item(Activity activity,List<ItemList> itemListsItems){
    this.activity=activity;
    this.itemListsItems=itemListsItems;
    pref = new Bookmark_SharedPref(activity);
}


@Override
public int getCount() {
    return itemListsItems.size();
}

@Override
public Object getItem(int position) {
    return itemListsItems.get(position);
}

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

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

    View v = convertView;
    ViewHolder holder;

    if(inflater == null){
        inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }
    if(convertView == null){
        convertView = inflater.inflate(R.layout.item_layout,null);

        holder = new ViewHolder();
        convertView.setTag(holder);
    }
    else{
        holder = (ViewHolder)convertView.getTag();
    }


    if(imageLoader == null){
        imageLoader = AppController.getInstance().getImageLoader();
    }




     holder.img = (NetworkImageView)convertView.findViewById(R.id.item_image);
    holder.Title = (TextView)convertView.findViewById(R.id.item_title);
    holder.Cat = (TextView)convertView.findViewById(R.id.item_category);

    holder.id = (TextView)convertView.findViewById(R.id.itemid);

    holder.Desc = (TextView)convertView.findViewById(R.id.item_description);

    holder.book = (ImageView)convertView.findViewById(R.id.bookmark_star);



    // getting blog data or the row
    ItemList il = itemListsItems.get(position);

    //setting image
    holder.img.setImageUrl(il.getImageUrl(), imageLoader);

    // setting title
    holder.Title.setText(il.getTitle());

    //setting category
    holder.Cat.setText(il.getCategory());


    //setting blog id
    holder.id.setText(il.getId());

    //setting description
    holder.Desc.setText(il.getDescription());

    //bookmarking the post
    holder.book.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            itemListsItems.get(position).isFav = !itemListsItems.get(position).isFav;
            ((ImageView)v.findViewById(R.id.bookmark_star)).setImageResource(itemListsItems.get(position).isFav ? R.mipmap.active_star : R.mipmap.inactive_star);

            if(itemListsItems.get(position).isFav){
                String data = Integer.toString(itemListsItems.get(position).id);
                Toast.makeText(v.getContext(),"fav hai "+data,Toast.LENGTH_SHORT).show();
                pref.addPref(data);
            } else {
                String data = Integer.toString(itemListsItems.get(position).id);
                Toast.makeText(v.getContext(),"not fav"+ data,Toast.LENGTH_SHORT).show();
                pref.removePref(data);
            }
            //notifyDataSetChanged();
        }
    });

    ((ImageView)convertView.findViewById(R.id.bookmark_star)).setImageResource(itemListsItems.get(position).isFav ? R.mipmap.active_star : R.mipmap.inactive_star);

    /*
    if(itemListsItems.get(position).isFav){
        String data = Integer.toString(itemListsItems.get(position).id);
        Toast.makeText(convertView.getContext(),"fav hai "+data,Toast.LENGTH_SHORT).show();
        pref.addPref(data);
    } else {
        String data = Integer.toString(itemListsItems.get(position).id);
        //Toast.makeText(convertView.getContext(),"not fav"+ data,Toast.LENGTH_SHORT).show();
        pref.removePref(data);
    }
    */
    return convertView;
}

private static class ViewHolder {
   public TextView Title, Desc,Cat,id;
    ImageView book;
    NetworkImageView img;
}

También tenga en cuenta hacer el diseño de la lista como android:focussable="true"y para el uso de ese botón / parámetro de texto android:focussable="false".

Mukul Aggarwal
fuente
corregido debería ser android: focusable = "false" no
enfocable
1

Agregue un android:focusable="false"atributo al botón y a la vista principal agregue un android:descendantFocusability="blocksDescendants"atributo como este.

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:descendantFocusability="blocksDescendants">

    <ImageButton
        android:id="@+id/sell_button"
        android:layout_width="wrap_content"
        android:focusable="false"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_sell" />
</RelativeLayout>
Süheyl Kawsara
fuente
0

Es sorprendente notar que la forma en que XML cambió hace que setonitemclicked en java funcione para mí.

android:descendantFocusability="blocksDescendants"
android:focusable="false"
android:focusableInTouchMode="false"
Waseem Minhas
fuente
0

Haga que el atributo principal en el que se puede hacer clic sea falso de esta manera android:clickable="false".

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:clickable="false"
    android:orientation="vertical">

De nuevo frente al problema, luego para todas las vistas secundarias agregue este falso en el que se puede hacer clic.

REMITH
fuente
0

No sé exactamente por qué, pero a veces cuando configura el adaptador, los oyentes se borran. Entonces, debe llamar setOnClickListenerdespués de setAdaptero setListAdapter.

Tiago Gouvêa
fuente
0

Eliminar android:clickable="true"de la vista personalizada interna del ListView.

Hamid Jolany
fuente