Android ListView child View setEnabled () y setClickable () no hacen nada

Estoy haciendo algo AsyncTask trabajar después de que el usuario haga clic en un elemento en mi ListView. Me gustaría deshabilitar el elemento para que no se pueda hacer clic dos veces. He simplificado el oyente de clics para que contenga solo este método, pero todavía no hace nada por mí, la vista se ve igual y se vuelve a hacer clic felizmente, para mi molestia.

public void onItemClick(AdapterView<?> parent, View clickedView,
  int position, long id) {
  item = (Episode) parent.getItemAtPosition(position);
  clickedView.setClickable(false);
  clickedView.setEnabled(false);
  clickedView.invalidate();
}

Mi vista para cada fila es personalizada LinearLayout con dos TextViews.

preguntado el 08 de enero de 11 a las 21:01

todos ustedes tienen razón. Ahora funciona, gracias.

4 Respuestas

Por lo tanto, es posible que también esté utilizando un adaptador personalizado. Si lo hace, anule estos métodos:

public boolean areAllItemsEnabled() {
    return false;
}

public boolean isEnabled(int position) {
    // return false if position == position you want to disable
}

Luego, cuando reciba un clic, dígale al adaptador cuál fue el último elemento en el que se hizo clic y devuelva falso en isEnabled para ese puesto. Por ejemplo, puede tener un método como este en su adaptador:

private int mLastClicked;
public void setLastClicked(int lastClicked){
    mLastClicked = lastClicked;
}

Respondido el 09 de enero de 11 a las 01:01

hola, estoy teniendo dificultades para conseguir la posición del último elemento en el que se hizo clic, ¿puedes iluminarme para esto? NoobMe

Si desea deshabilitar el elemento, haga clic en la vista de lista, use clickedView.setClickable(true);

Respondido 05 Abr '12, 15:04

Esto suena muy mal, pero por la razón que sea, funciona. Extraño, tal vez un profesional pueda aclararnos por qué setClickable (true) realmente tendrá el efecto deseado de hacer que la vista no se pueda hacer clic. - Bachi

indead! Parece un error en el sistema. - user717572

Creo que esto no es un error. De esta manera clickedView intercepta el clic. El elemento de la lista no responderá a ningún clic porque clickedView los intercepta, por lo que el elemento de la lista no se resaltará. - mneri

¡DIOS MÍO! ¡Acabo de pasar horas y horas tratando de lograr esto! Estaba pensando en crear selectores personalizados o color de fondo para ocultar el efecto de selector ... ¡Muchas gracias! - FMCorz

Es realmente extraño ... setClickable (true) significa que no se puede hacer clic. Espero que esto no se solucione en el futuro ... XDD - derjohng

Tu problema no está del todo claro. Estoy interpretando tu pregunta como que estás esperando onItemClick() para no ser llamado basado en tu setEnabled() y setClickable() llamadas.

No me sorprende que no funcione, ya que onItemClick() es algo ListView lo hace, no la vista del niño. Intenta anular areAllItemsEnabled() y isEnabled() en su ListAdapter en vez.

Respondido el 09 de enero de 11 a las 01:01

Hay varias razones por las que su enfoque no funcionará.

1) onItemClick solo se llama debido a eventos de teclado. Específicamente KeyKevent.KEYCODE_ENTER. No se llama a través de ninguna otra ruta de código. Por lo tanto, manejar eso solo es útil si está intentando proporcionar soporte de teclado / trackball.

Código fuente de Android para métodos relevantes de AbsListView:

public boolean onKeyUp(int keyCode, KeyEvent event) {
    switch (keyCode) {
    case KeyEvent.KEYCODE_DPAD_CENTER:
    case KeyEvent.KEYCODE_ENTER:
        if (!isEnabled()) {
            return true;
        }
        if (isClickable() && isPressed() &&
                mSelectedPosition >= 0 && mAdapter != null &&
                mSelectedPosition < mAdapter.getCount()) {

            final View view = getChildAt(mSelectedPosition - mFirstPosition);
            if (view != null) {
                performItemClick(view, mSelectedPosition, mSelectedRowId);
                view.setPressed(false);
            }
            setPressed(false);
            return true;
        }
        break;
    }
    return super.onKeyUp(keyCode, event);
}

public boolean performItemClick(View view, int position, long id) {
    if (mOnItemClickListener != null) {
        playSoundEffect(SoundEffectConstants.CLICK);
        mOnItemClickListener.onItemClick(this, view, position, id);
        return true;
    }

    return false;
}

2) Está configurando la información en la que se puede hacer clic directamente en la vista. Las vistas que se muestran a través de cualquier AdapterView son etéreos. Se crean a petición de la AdapterView y solo existen mientras el AdapterView los necesita. No debe establecer ningún dato sobre ellos que desee conservar. Puedes llamar setEnabled y setClickable sobre ellos para un efecto inmediato, pero si desea que esa información persista, debe almacenarla en algún lugar donde Adapter tiene acceso para que pueda ser recreado cuando el AdapterView recrea el View para ese puesto.

3) Necesita manejar el onClick evento para el real View haciendo clic. Dónde manejar esto depende de usted. El mejor lugar es probablemente tu Adapter que luego puede pasarlo o no a su Activity dependiendo de cuáles sean sus requisitos de diseño. Ahí es donde necesita manejar sus eventos táctiles.

Vea este código para una actividad simple:

public class PhoneTesting extends Activity {
    private static final String TAG = "PhoneTesting";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Log.d(TAG, "onCreate()");

        List<String> strings = new ArrayList<String>();
        for(int i = 0 ; i < 20 ; i++) {
            strings.add(Integer.toString(i));
        }

        ListView list = (ListView) this.findViewById(R.id.list);

        list.setAdapter(new SimpleAdapter(this, 0, 0, strings));
        list.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Log.d(TAG, "onItemClick: " + id);
            }
        });

    }

    class SimpleAdapter extends ArrayAdapter<String> implements OnClickListener {
        SimpleAdapter(Context context, int resource, int textViewResourceId, List<String> objects) {
            super(context, resource, textViewResourceId, objects);
        }

        SimpleAdapter(Context context, int resource, int textViewResourceId, String[] objects) {
            super(context, resource, textViewResourceId, objects);
        }

        SimpleAdapter(Context context, int resource, int textViewResourceId) {
            super(context, resource, textViewResourceId);
        }

        SimpleAdapter(Context context, int textViewResourceId, List<String> objects) {
            super(context, textViewResourceId, objects);
        }

        SimpleAdapter(Context context, int textViewResourceId, String[] objects) {
            super(context, textViewResourceId, objects);
        }

        SimpleAdapter(Context context, int textViewResourceId) {
            super(context, textViewResourceId);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            TextView b = position % 2 == 0 ? new Button(this.getContext()) : new TextView(this.getContext());
            b.setText(this.getItem(position));

            b.setOnClickListener(this);

            return b;
        }

        @Override
        public void onClick(View v) {
            TextView t = (TextView) v;
            Log.d(TAG, "onClick: " + t.getText());
        }

        @Override
        public boolean isEnabled(int position) {
            return position % 2 == 0 ? false : true;
        }

    }
}

Si ejecuta este código y hace clic en cualquiera de los Views en el ListView notará en la salida de logcat que solo onClick está siendo llamado. onItemClick nunca se llama.

También tenga en cuenta que isEnabled en el adaptador no parece tener efecto si el View se puede hacer clic o no. No estoy seguro de cómo interpretar eso. Sin embargo, lo que eso significa es que si desea controlar esa propiedad del View esta Adapter necesita establecer que cuando el View se crea y de alguna manera mantener esa información.

Respondido el 09 de enero de 11 a las 02:01

También necesitaría anular areAllItemsEnabled() en el Adaptador, pero gracias - Axarydax

Sí, me olvidé de ese. still onItemClick solo se llama a través de eventos de teclado. - Rich Schuler

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.