2010-10-19 7 views
15

J'ai deux fichiers de mise en page dans mon application. Aussi j'ai l'activité étend ListActivity. Chaque élément de cette activité semble prendre en compte le fichier de disposition item.xml. J'essaie d'obtenir un menu contextuel lorsque j'appuie longuement sur l'élément, mais je ne le vois pas.ListView personnalisé et menu contextuel. Comment l'obtenir?

Dans mon activité, j'essaie de registerForContextMenu (getListView()) et passer outre deux méthodes

@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> 

Tout cela doesn ne fonctionne pas. Peut-être que la raison est dans LinearLayout? Je trouve également un sujet similaire Android: Context menu doesn't show up for ListView with members defined by LinearLayout? mais j'ai un élément de liste plus compliqué.

Comment obtenir le menu contextuel dans mon cas?

Toujours dans mon activité, j'ai classe interne étend ArrayAdapter. Dans cette classe dans la méthode getView, je peux définir OnCreateContextMenuListener sur chaque vue, après que ce menu contextuel est apparu, mais je ne sais pas comment gérer les clics sur les éléments. Si j'essaie de le faire dans la méthode onContextItemSelected, l'objet item.getMenuInfo() est toujours null et je ne peux pas obtenir d'informations à ce sujet.

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

Merci. J'espère pour votre aide.

Répondre

33

J'ai eu la solution, mon ami m'a aidé! J'espère que cette information sera utile à quelqu'un. Il s'agit d'un code de classe complet avec ArrayAdapter et la mise en page complexe et le menu contextuel.

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 
     } 

    } 
} 

laissez-moi savoir si quelqu'un va trouver une meilleure approche. Merci!

+7

J'ai trouvé une petite amélioration - 'v.setOnCreateContextMenuListener (null)'. – m039

+0

Merci @Georgy. cela m'a aidé –

+0

fonctionne comme un charme +1 – mprabhat

0

Je ne pense pas que vous vouliez attacher un menu contextuel aux éléments listView spécifiques. En appelant registerForContextMenu (getListView()), vous devriez obtenir cette fonctionnalité gratuitement. Je connecterais votre application à un débogueur après avoir supprimé les hooks contextMenu du code de l'adaptateur et défini un point d'arrêt à l'intérieur de onCreateContextMenu(). Mon soupçon est qu'il est appelé, mais la disposition qui est gonflée n'est pas ce que vous attendez.

+0

Non, je ne le sais pas. J'ai défini des points d'arrêt dans la méthode onCreateContextMenu et exécuté mon application en mode débogage, mais l'exécution de l'application n'atteint aucun point d'arrêt. –

0

Le problème de base est que l'élément est dessiné par la deuxième mise en page item.xml - de sorte que l'élément racine (LinearLayout) correspond à ce qui est enfoncé longtemps plutôt qu'à ce que le ListView d'origine a fourni. En tant que tel, lorsque vous gonflez la mise en page item.xml, vous devez appeler setOnCreateContextMenuListener comme vous l'avez fait dans le second exemple. Le problème avec ceci est qu'il n'y a aucun moyen pour la mise en page de item.xml (qui est un LinearLayout) de communiquer à l'activité quelle position a été choisie. Cela est dû au fait que LinearLayout ne remplace pas la méthode getContextMenuInfo() qui, dans un ListView, renvoie un AdapterView.AdapterContextMenuInfo (comme tout le monde semble forcer ContextMenuInfo à). Donc, idéalement, vous voulez créer votre propre descendant LinearLayout qui rende le getContextMenuInfo public, crée un faux s'il n'y en a pas, et quand onCreateContextMenu est appelé dans votre adaptateur personnalisé, il l'attrape à partir de votre LinearLayout personnalisé. et met la position/id là-dedans, que votre activité peut retirer.

C'est ce que j'ai fait dans ma propre application et cela fonctionne très bien et est une solution générique - vous pouvez en fait y mettre tout ce que vous voulez tant qu'il implémente l'interface ContextMenuInfo (qui est juste une interface de marqueur).

7

Après segments de code de ComplexObjectAdapter de classe imbriquée, énumérés dans la réponse de Georgy Gobozov, ne sont pas vraiment nécessaires:

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

Il fonctionne parce que dans la fonction setOnCreateContextMenuListener() de vue de la classe, il appelle la fonction setLongClickable (true):

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

cela signifie que le problème peut être résolu en définissant la propriété à long cliquables pour chaque élément enfant, après sa création:

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

ou il réglage peut être résolu aussi cette propriété dans le fichier de configuration XML de la vue de la liste des éléments enfants, par exemple:

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

    <!-- Child elements --> 

</LinearLayout> 
+0

Nice, savez-vous s'il est possible de le laisser également mettre en surbrillance lorsqu'il est tapé et long-cliqué? – NoBugs

0

Je ne maintenant pourquoi, il est nécessaire de définir un null OnCreateContextMenuListener sur chaque ligne de la liste (en plus de registerForContextMenu (...) et mettre en œuvre onCreateContextMenu (...) et onContextItemSelected (...)

1

en fait, il vous suffit de faire sur le long cliquable en appelant

v.setLongClickable(true); 

Il n'est pas nécessaire de régler le setOnCreateContextMenuListener, car c'est la seule chose à faire.

Questions connexes