2010-10-19 28 views
15

Tengo dos archivos de diseños en mi aplicación. También tengo Activity extends ListActivity. Cada elemento de esta actividad parece considerar el archivo de diseño item.xml. Estoy tratando de obtener el menú contextual cuando hago una pulsación larga en el elemento, pero no lo veo.ListView personalizado y menú contextual. ¿Cómo conseguirlo?

En mi actividad me tratando de registerForContextMenu (getListView()) y anular dos métodos

@Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     Bundle bundle = this.getIntent().getExtras(); 
     registerForContextMenu(getListView()); 
     new PopulateAdapterTask().execute(ACTION_SELECT); 
    } 

    @Override 
     public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { 
      MenuInflater inflater = getMenuInflater(); 
      inflater.inflate(R.menu.context_menu, menu); 
     } 


     @Override 
     public boolean onContextItemSelected(MenuItem item) { 
      AdapterView.AdapterContextMenuInfo info; 
      try { 
       info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo(); 
      } catch (ClassCastException e) { 
       return false; 
      } 
      long id = getListAdapter().getItemId(info.position); 
      Log.d(TAG, "id = " + id); 
      return true; 
     } 

Main.xml

<?xml version="1.0" encoding="utf-8"?> 
<TabHost xmlns:android="http://schemas.android.com/apk/res/android" 
     android:id="@android:id/tabhost" 
     android:layout_width="fill_parent" 
     android:layout_height="fill_parent"> 
    <LinearLayout 
      android:orientation="vertical" 
      android:layout_width="fill_parent" 
      android:layout_height="fill_parent" 
      android:padding="5dp"> 
     <TabWidget 
       android:id="@android:id/tabs" 
       android:layout_width="fill_parent" 
       android:layout_height="wrap_content"/> 
     <FrameLayout 
       android:id="@android:id/tabcontent" 
       android:layout_width="fill_parent" 
       android:layout_height="fill_parent" 
       android:padding="5dp"> 
      <ListView 
        android:id="@+id/list" 
        android:layout_width="fill_parent" 
        android:layout_height="fill_parent" 
        /> 

     </FrameLayout> 

    </LinearLayout> 

</TabHost> 

Item.xml

<?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="wrap_content" 
     > 
    <ImageView 
      android:id="@+id/icon" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      /> 
    <TextView 
      android:id="@+id/info" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:padding="10dp" 
      android:textSize="15sp" 
      android:singleLine="true" 
      android:ellipsize="marquee" 
      android:scrollHorizontally = "true" 
      android:maxWidth="200dp" 
      /> 


    <LinearLayout 
      android:layout_width="fill_parent" 
      android:layout_height="fill_parent" 
      android:gravity="right" 
      > 
     <ImageButton 
       android:id="@+id/button" 
       android:layout_width="wrap_content" 
       android:layout_height="fill_parent" 
       android:background="@null" 
       android:paddingRight="10dp"     
       android:paddingLeft="10dp" 


       /> 
    </LinearLayout> 

</LinearLayout> 

Todo esto doesn no funciona Tal vez el motivo esté en LinearLayout? También encuentro un tema similar Android: Context menu doesn't show up for ListView with members defined by LinearLayout? pero tengo un elemento de lista más complicado.

¿Cómo obtener el menú contextual en mi caso?

También en mi actividad I have inner class extends ArrayAdapter. En esta clase, en el método getView, puedo configurar OnCreateContextMenuListener en cada Vista, después de que aparece el menú contextual, pero no sé cómo manejar los clics de los elementos. Si estoy intentando hacer esto en el método onContextItemSelected, el objeto item.getMenuInfo() siempre es nulo y no puedo obtener información de él.

private class ChannelAdapter extends ArrayAdapter<Channel> { 

     private List<Channel> channels; 

     public ChannelAdapter(Context context, int textViewResourceId, List<Channel> objects) { 
      super(context, textViewResourceId, objects); 
      this.channels = objects; 
     } 


     @Override 
     public View getView(int position, View convertView, ViewGroup parent) { 
      View v = convertView; 
      if (v == null) { 
       LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
       v = vi.inflate(R.layout.station_item, null); 
      } 


       v.setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() { 
        public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { 
         MenuInflater inflater = getMenuInflater(); 
         inflater.inflate(R.menu.context_menu, menu); 
        } 
       }); 

Gracias. Espero tu ayuda

Respuesta

33

¡Tengo solución, mi amigo me ayudó! Espero que esta información sea útil para alguien. Este es el código de clase completo con ArrayAdapter y la disposición de la lista compleja y el menú contextual.

public class ComplexListActivity extends ListActivity { 
    /** 
    * Called when the activity is first created. 
    */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 

     super.onCreate(savedInstanceState); 
     setListAdapter(new ComplexObjectAdapter(this, R.layout.item, getComplexObjects())); 
     registerForContextMenu(getListView()); 
    } 

    private List getComplexObjects() { 
     List<ComplexObject> list = new ArrayList<ComplexObject>(); 
     list.add(new ComplexObject("1", "1", getResources().getDrawable(R.drawable.icon))); 
     list.add(new ComplexObject("2", "2", getResources().getDrawable(R.drawable.icon))); 
     list.add(new ComplexObject("3", "3", getResources().getDrawable(R.drawable.icon))); 
     list.add(new ComplexObject("4", "4", getResources().getDrawable(R.drawable.icon))); 
     list.add(new ComplexObject("5", "5", getResources().getDrawable(R.drawable.icon))); 
     list.add(new ComplexObject("6", "6", getResources().getDrawable(R.drawable.icon))); 
     list.add(new ComplexObject("7", "7", getResources().getDrawable(R.drawable.icon))); 
     list.add(new ComplexObject("8", "8", getResources().getDrawable(R.drawable.icon))); 
     list.add(new ComplexObject("9", "9", getResources().getDrawable(R.drawable.icon))); 
     return list; 
    } 


    @Override 
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { 
     MenuInflater inflater = getMenuInflater(); 
     inflater.inflate(R.menu.context_menu, menu); 
    } 


    @Override 
    public boolean onContextItemSelected(MenuItem item) { 
     AdapterView.AdapterContextMenuInfo info; 
     try { 
      info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo(); 
     } catch (ClassCastException e) { 
      Log.e("", "bad menuInfo", e); 
      return false; 
     } 
     long id = getListAdapter().getItemId(info.position); 
     Log.d("", "id = " + id); 
     Toast.makeText(this, "id = " + id, Toast.LENGTH_SHORT).show(); 
     return true; 
    } 

    private class ComplexObjectAdapter extends ArrayAdapter<ComplexObject> implements View.OnCreateContextMenuListener { 

     private List<ComplexObject> objects; 

     public ComplexObjectAdapter(Context context, int textViewResourceId, List<ComplexObject> objects) { 
      super(context, textViewResourceId, objects); 
      this.objects = objects; 
     } 


     @Override 
     public View getView(int position, View convertView, ViewGroup parent) { 
      View v = convertView; 
      if (v == null) { 
       LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
       v = vi.inflate(R.layout.item, null); 
      } 
      final ComplexObject o = objects.get(position); 
      if (o != null) { 

       TextView textlInfo = (TextView) v.findViewById(R.id.info); 
       textlInfo.setText(o.getName()); 

       ImageView channelIcon = (ImageView) v.findViewById(R.id.icon); 
       channelIcon.setAdjustViewBounds(true); 
       channelIcon.setMaxHeight(30); 
       channelIcon.setMaxWidth(30); 
       channelIcon.setImageDrawable(o.getLogo()); 


       ImageButton button = (ImageButton) v.findViewById(R.id.button); 
       button.setImageResource(R.drawable.icon); 
       v.setOnCreateContextMenuListener(this); 

      } 
      return v; 
     } 

     public void onCreateContextMenu(ContextMenu contextMenu, View view, ContextMenu.ContextMenuInfo contextMenuInfo) { 
      // empty implementation 
     } 

    } 
} 

hágamelo saber si alguien encontrará un mejor enfoque. ¡Gracias!

+7

He encontrado una pequeña mejora: 'v.setOnCreateContextMenuListener (null)'. – m039

+0

Gracias @Georgy. esto me ayudó –

+0

funciona como un amuleto +1 – mprabhat

0

No creo que desee adjuntar un menú contextual a la lista específica de elementos de la vista. Al llamar a registerForContextMenu (getListView()) debería obtener esa funcionalidad de forma gratuita. Conectaría su aplicación a un depurador después de eliminar los ganchos contextMenu del código del adaptador y establecer un punto de interrupción dentro de onCreateContextMenu(). Mi sospecha es que se llama pero el diseño que se está inflando no es lo que se espera.

+0

No, no lo hago así. Establecí los puntos de interrupción en el método onCreateContextMenu y ejecuto mi aplicación en modo de depuración, pero la ejecución de la aplicación no llega a ningún punto de interrupción. –

0

El problema básico es que el elemento se dibuja en el segundo diseño item.xml, por lo que el elemento raíz (LinearLayout) es lo que se presiona durante mucho tiempo en lugar de lo que proporcionaba el ListView original. Como tal, cuando inflas el diseño item.xml, necesitas llamar al setOnCreateContextMenuListener como lo has hecho en el segundo ejemplo. El problema con esto es que no hay forma de que el diseño de item.xml (que es un LinearLayout) se comunique nuevamente a la actividad qué posición se eligió. Esto se debe a que LinearLayout no anula el método getContextMenuInfo() que en un ListView devuelve un AdapterView.AdapterContextMenuInfo (ya que todos parecen forzar su ContextMenuInfo a).

Así que, idealmente, desea crear su propio descendiente LinearLayout que haga pública la getContextMenuInfo, cree una falsa si no hay una allí, y cuando se llama a onCreateContextMenu en su adaptador personalizado, lo toma de su LinearLayout personalizado y coloca la posición/identificación allí, que tu actividad puede sacar.

Esto es lo que he hecho en mi propia aplicación y funciona muy bien y es una solución genérica; de hecho, puedes poner lo que quieras siempre que implemente la interfaz ContextMenuInfo (que es solo una interfaz de marcador))

7

siguientes segmentos de código de ComplexObjectAdapter clase anidada, que aparece en la respuesta de Georgy Gobozov, no son realmente necesarios:

@Override 
    public View getView(int position, View convertView, ViewGroup parent) { 
     View v = convertView; 
     if (v == null) { 
      LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
      v = vi.inflate(R.layout.item, null); 
     } 
     final ComplexObject o = objects.get(position); 
     if (o != null) { 

      TextView textlInfo = (TextView) v.findViewById(R.id.info); 
      textlInfo.setText(o.getName()); 

      ImageView channelIcon = (ImageView) v.findViewById(R.id.icon); 
      channelIcon.setAdjustViewBounds(true); 
      channelIcon.setMaxHeight(30); 
      channelIcon.setMaxWidth(30); 
      channelIcon.setImageDrawable(o.getLogo()); 


      ImageButton button = (ImageButton) v.findViewById(R.id.button); 
      button.setImageResource(R.drawable.icon); 
      // NOT NEEDED 
      v.setOnCreateContextMenuListener(this); 

     } 
     return v; 
    } 

// NOT NEEDED 
public void onCreateContextMenu(ContextMenu contextMenu, View view, ContextMenu.ContextMenuInfo contextMenuInfo) { 
      // empty implementation 
} 

Simplemente funciona porque en el interior del setOnCreateContextMenuListener función() de la clase Vista, llama a la setLongClickable función (verdadero):

/** 
* Register a callback to be invoked when the context menu for this view is 
* being built. If this view is not long clickable, it becomes long clickable. 
* 
* @param l The callback that will run 
* 
*/ 
public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) { 
    if (!isLongClickable()) { 
     setLongClickable(true); 
    } 
    mOnCreateContextMenuListener = l; 
} 

se significa que el problema puede ser resuelto estableciendo la propiedad larga con enlace para cada elemento secundario, después de su creación:

@Override 
    public View getView(int position, View convertView, ViewGroup parent) { 
     View v = convertView; 
     if (v == null) { 
      LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
      v = vi.inflate(R.layout.item, null); 
      // SET LONG CLICKABLE PROPERTY 
      v.setLongClickable(true); 
     } 
     final ComplexObject o = objects.get(position); 
     if (o != null) { 

      TextView textlInfo = (TextView) v.findViewById(R.id.info); 
      textlInfo.setText(o.getName()); 

      ImageView channelIcon = (ImageView) v.findViewById(R.id.icon); 
      channelIcon.setAdjustViewBounds(true); 
      channelIcon.setMaxHeight(30); 
      channelIcon.setMaxWidth(30); 
      channelIcon.setImageDrawable(o.getLogo()); 


      ImageButton button = (ImageButton) v.findViewById(R.id.button); 
      button.setImageResource(R.drawable.icon); 
      // NOT NEEDED 
      // v.setOnCreateContextMenuListener(this); 

     } 
     return v; 
    } 

o también puede ser resuelto establecer esta propiedad en el archivo de diseño de XML en la lista Ver elementos secundarios, por ejemplo:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:longClickable="true"> 

    <!-- Child elements --> 

</LinearLayout> 
+0

Bien, ¿sabes si también es posible dejarlo resaltar cuando se toca y se hace clic con el botón largo? – NoBugs

0

no lo hago ahora por qué, es necesario establecer un nulo OnCreateContextMenuListener en cada fila de la lista (además de registerForContextMenu (...) e implementar onCreateContextMenu (...) y onContextItemSelected (...)

1

en realidad, sólo tiene que hacer Ver larga puede hacer clic llamando

v.setLongClickable(true); 

No es necesario configurar el dummy setOnCreateContextMenuListener, porque así es: establece el elemento con el que se puede hacer clic.

Cuestiones relacionadas