2010-10-19 4 views
15

У меня есть два файла макетов в моем приложении. Также у меня есть Activity Extends ListActivity. Каждый элемент этого действия рассматривает элемент layout.xml. Я пытаюсь получить контекстное меню, когда долго нажимает на элемент, но я его не вижу.Пользовательское меню ListView и контекстное меню. Как его получить?

В моей деятельности я пытаюсь registerForContextMenu (getListView()) и переопределить два метода

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

Все это Безразлично Не работай. Может, причина в LinearLayout? Я также нашел аналогичную тему Android: Context menu doesn't show up for ListView with members defined by LinearLayout?, но у меня есть более сложный элемент списка.

Как получить контекстное меню в моем случае?

Также в моей деятельности у меня внутренний класс расширяет ArrayAdapter. В этом классе в методе getView я могу установить OnCreateContextMenuListener на каждом представлении, после чего появляется контекстное меню, но я не знаю, как обрабатывать клики по элементам. Если я пытаюсь сделать это в методе onContextItemSelected, объект item.getMenuInfo() всегда имеет значение null, и я не могу получить некоторую информацию от него.

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

Спасибо. Надеюсь на вашу помощь.

ответ

33

У меня есть решение, мой друг помог мне! Надеюсь, эта информация поможет кому-то. Это полный код класса с ArrayAdapter и сложным списком и контекстным меню.

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 
     } 

    } 
} 

дайте мне знать, если кто-то найдет лучший подход. Благодаря!

+7

Я нашел небольшое улучшение - 'v.setOnCreateContextMenuListener (null)'. – m039

+0

Спасибо @Georgy. это помогло мне –

+0

работает как шарм +1 – mprabhat

0

Я не думаю, что вы хотите прикрепить контекстное меню к определенным элементам listView. Вызывая registerForContextMenu (getListView()), вы должны получить эту функциональность бесплатно. Я бы привязал ваше приложение к отладчику после удаления крючков contextMenu из кода адаптера и установил точку останова внутри onCreateContextMenu(). Мое подозрение в том, что его называют, но макет, который раздувается, не то, что вы ожидаете.

+0

Нет, я не так уж и так. Я установил точки останова в методе onCreateContextMenu и запустил приложение в режиме отладки, но выполнение приложения не достигло точки останова. –

0

Основная проблема заключается в том, что элемент нарисован на втором элементе item.xml - поэтому корневой элемент (LinearLayout) - это то, что долгое нажатие, а не то, что предоставил оригинальный ListView. Таким образом, когда вы раздуваете макет item.xml, вам нужно вызвать setOnCreateContextMenuListener, как вы это сделали во втором примере. Проблема заключается в том, что макет из item.xml (который является LinearLayout) не подходит для связи с объектом, в котором была выбрана позиция. Это связано с тем, что LinearLayout не переопределяет метод getContextMenuInfo(), который в ListView возвращает AdapterView.AdapterContextMenuInfo (поскольку все, кажется, принуждают их ContextMenuInfo).

В идеале вы хотите создать собственный потомок LinearLayout, который делает публичным getContextMenuInfo, создает поддельный, если его там нет, и когда onCreateContextMenu вызывается в вашем пользовательском адаптере, он захватывает его из вашего пользовательского LinearLayout и помещает туда позицию/id, которую ваша деятельность может вытащить.

Это то, что я сделал в своем приложении, и он работает очень хорошо и является универсальным решением - на самом деле вы можете разместить там что угодно, пока он реализует интерфейс ContextMenuInfo (который является всего лишь интерфейсом маркера).

7

После сегментов кода из вложенного класса ComplexObjectAdapter, перечисленных в ответе Георгий Гобозов, в самом деле не нужны:

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

Он просто работает, потому что внутри функции setOnCreateContextMenuListener() из класса View, он вызывает функцию setLongClickable (правда):

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

это означает, что проблема может быть решена установкой свойства Long кликабельна для каждого дочернего элемента, после его создания:

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

или она также может быть решена установкой этого свойства в файл макета XML из дочерних элементов списка, например:

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

    <!-- Child elements --> 

</LinearLayout> 
+0

Приятно, знаете ли вы, можно ли также выделить его при нажатии и длительном нажатии? – NoBugs

0

Я не теперь, почему необходимо установить нулевой OnCreateContextMenuListener на каждом списке подряд (в дополнение к registerForContextMenu (...) и осуществлять onCreateContextMenu (...) и onContextItemSelected (...)

1

на самом деле, вам просто нужно сделать вид долго кликабельным по телефону

v.setLongClickable(true); 

Не нужно устанавливать манекен setOnCreateContextMenuListener, потому что он делает именно это - элемент набора с длинным кликом.

Смежные вопросы