2010-10-19 9 views
15

Ich habe zwei Layoutdateien in meiner App. Auch ich habe Aktivität erweitert ListActivity. Jedes Element dieser Aktivität berücksichtigt die item.xml-Layoutdatei. Ich versuche, das Kontextmenü zu erhalten, wenn ich lange auf den Gegenstand drücke, aber ich sehe es nicht.Benutzerdefiniertes ListView und Kontextmenü. Wie bekomme ich es?

In meiner Tätigkeit versuche ich zu registerForContextMenu (getListView()) und überschreiben zwei Methoden

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

All dies doesn arbeite nicht. Vielleicht liegt der Grund in LinearLayout? Ich finde auch ähnliches Thema Android: Context menu doesn't show up for ListView with members defined by LinearLayout?, aber ich habe komplizierteres Listenelement.

Wie bekomme ich ein Kontextmenü in meinem Fall?

Auch in meiner Tätigkeit habe ich innere Klasse erweitert ArrayAdapter. In dieser Klasse in der Methode "getView" kann ich OnCreateContextMenuListener für jede Ansicht festlegen, nachdem das Kontextmenü angezeigt wird, aber ich weiß nicht, wie mit Elementklicks verfahren werden soll. Wenn ich dies in der Methode onContextItemSelected versuche, ist das Objekt item.getMenuInfo() immer null und ich kann keine Informationen von ihm erhalten.

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

Danke. Hoffe auf deine Hilfe.

Antwort

33

Ich habe eine Lösung, mein Freund hat mir geholfen! Ich hoffe, diese Information wird für jemanden hilfreich sein. Dies ist vollständiger Klassencode mit ArrayAdapter und komplexem Listenlayout und Kontextmenü.

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 
     } 

    } 
} 

lassen Sie mich wissen, ob jemand einen besseren Ansatz finden wird. Vielen Dank!

+7

Ich habe eine kleine Verbesserung gefunden - 'v.setOnCreateContextMenuListener (null)'. – m039

+0

Danke @Georgy. das hat mir geholfen –

+0

funktioniert wie ein Charme +1 – mprabhat

0

Ich glaube nicht, dass Sie den einzelnen ListView-Elementen ein Kontextmenü hinzufügen möchten. Wenn Sie registerForContextMenu (getListView()) aufrufen, sollten Sie diese Funktionalität kostenlos erhalten. Ich würde Ihre Anwendung mit einem Debugger verbinden, nachdem Sie die contextMenu-Hooks aus dem Adaptercode entfernt und einen Breakpoint innerhalb von onCreateContextMenu() gesetzt haben. Mein Verdacht ist, dass es aufgerufen wird, aber das Layout, das aufgeblasen wird, ist nicht das, was Sie erwarten.

+0

Nein, ich nicht thynk so. Ich setze Haltepunkte in der onCreateContextMenu-Methode und führe meine Anwendung im Debug-Modus aus, aber die Ausführung der Anwendung erreicht keinen Haltepunkt. –

0

Das grundlegende Problem ist, dass das Element von der zweiten item.xml-Layout gezeichnet wird - so ist das Stammelement (LinearLayout), was lang gedrückt wird, anstatt was das ursprüngliche ListView zur Verfügung gestellt. Wenn Sie also das label.xml-Layout aufblasen, müssen Sie den setOnCreateContextMenuListener aufrufen, wie Sie es im zweiten Beispiel tatsächlich getan haben. Das Problem dabei ist, dass es für das Layout von item.xml (welches ein LinearLayout ist) nicht möglich ist, zurück zu der Aktivität zu kommunizieren, welche Position ausgewählt wurde. Dies liegt daran, dass das LinearLayout die Methode getContextMenuInfo() nicht überschreibt, die in einer ListView eine AdapterView.AdapterContextMenuInfo zurückgibt (wie alle ihre ContextMenuInfo zu erzwingen scheinen).

Also idealerweise möchten Sie Ihren eigenen LinearLayout-Nachfolger erstellen, der getContextMenuInfo öffentlich macht, einen falschen erstellt, wenn dort keiner vorhanden ist, und wenn onCreateContextMenu in Ihrem benutzerdefinierten Adapter aufgerufen wird, wird es von Ihrem benutzerdefinierten LinearLayout abgerufen und legt die Position/ID dort hinein, die deine Aktivität herausziehen kann.

Dies ist, was ich in meiner eigenen Anwendung getan habe und es funktioniert sehr schön und ist eine generische Lösung - Sie können tatsächlich alles, was Sie mögen, dort einfügen, solange es die ContextMenuInfo Schnittstelle implementiert (die nur eine Marker-Schnittstelle ist)).

7

Nach Segmenten von Code aus verschachtelter Klasse ComplexObjectAdapter, aufgelistet in Georgy Gobozov Antwort, die nicht wirklich benötigt:

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

Es funktioniert nur, weil innerhalb der Funktion setOnCreateContextMenuListener() aus der Klasse Ansicht, ruft er die Funktion 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; 
} 

es bedeutet, das Problem für jedes Kind Element gelöst werden kann die Lang klickbare-Eigenschaft, nachdem es erstellt wird:

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

oder es kann diese Eigenschaft auch in der XML-Layout-Datei der Child-Liste Ansichtselemente gelöst wird Einstellung, zum Beispiel:

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

    <!-- Child elements --> 

</LinearLayout> 
+0

Schön, wissen Sie, ob es möglich ist, auch markieren, wenn angezapft und lange geklickt? – NoBugs

0

ich nicht jetzt, warum es notwendig ist, eine Null zu setzen OnCreateContextMenuListener auf jeder Listenzeile (zusätzlich zu registerForContextMenu (...) und implementieren onCreateContextMenu (...) und onContextItemSelected (...)

1

Eigentlich müssen Sie nur anzeigen lange klickbare machen, indem

v.setLongClickable(true); 
Aufruf

Es ist nicht erforderlich, Dummy setOnCreateContextMenuListener zu setzen, weil es genau das ist - Set ist das Element lange klickbar.

Verwandte Themen