2013-05-02 6 views
4

J'implémente un ListActivity et ListFragment et voudrais permettre à l'utilisateur d'utiliser des robinets courts et longs - être court pour éditer/montrer les détails de l'article et appuyez longuement pour faire apparaître un menu contextuel avec l'option de supprimer l'article. Toutefois, je ne semble pas pouvoir déclencher le onCreateContextMenu. onListItemClick fonctionne très bien et capture tous les taps, courts ou longs. Le ListFragment est rempli à l'aide d'un SimpleCursorAdaptor et d'un LoaderManager légèrement personnalisés, sans utiliser de fichier de mise en page.Android ListFragment: comment avoir à la fois onListItemClick et onContextItemSelected?

Est-il possible d'avoir les deux?

code ...

LocationsListFragment.java 

package com.level3.connect.locations; 

//import removed for brevity 

public class LocationsListFragment extends SherlockListFragment implements LoaderManager.LoaderCallbacks<Cursor>{ 

private static final int DELETE_ID = Menu.FIRST + 1;  

private SimpleCursorAdapter adapter; 
private OnLocationSelectedListener locationSelectedListener; 

// the activity attaching to this fragment should implement this interface 
public interface OnLocationSelectedListener { 
    public void onLocationSelected(String locationId); 
}  

@Override 
public void onCreate(Bundle savedInstanceState) { 

    super.onCreate(savedInstanceState); 

    // Fields from the database (projection) 
    // Must include the _id column for the adapter to work 
    String[] from = new String[] { LocationsTable.LOCATION_NAME, 
      LocationsTable.LOCATION_PHONE_NAME }; 
    // Fields on the UI to which we map 
    int[] to = new int[] { R.id.titleText, R.id.phoneText }; 

    // connect to the database 
    getLoaderManager().initLoader(0, null, this); 
    adapter = new LocationCursorAdapter(getActivity(), 
      R.layout.location_row, null, from, to, 0); 

    setListAdapter(adapter); 
} 

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, 
     Bundle savedInstanceState) { 
    View root = super.onCreateView(inflater, container, savedInstanceState);  
    registerForContextMenu(root); //this is called fine 
    return root; 
} 

// hook up listening for the user selecting a location in the list 
@Override 
public void onAttach(Activity activity) { 
    super.onAttach(activity); 
    try { 
     locationSelectedListener = (OnLocationSelectedListener) activity; 
    } catch (ClassCastException e) { 
     throw new ClassCastException(activity.toString() 
       + " must implement OnLocationSelectedListener"); 
    } 
} 

// handle user tapping a location - show a detailed view - this works fine 
@Override 
public void onListItemClick(ListView l, View v, int position, long id) { 
    String projection[] = { LocationsTable.KEY_ID }; 
    Cursor locationCursor = getActivity().getContentResolver().query(
      Uri.withAppendedPath(DatabaseContentProvider.CONTENT_URI, 
        String.valueOf(id)), projection, null, null, null); 
    if (locationCursor.moveToFirst()) { 
     String locationUrl = locationCursor.getString(0); 
     locationSelectedListener.onLocationSelected(locationUrl); 
    } 
    locationCursor.close(); 
} 

// Context menu - this is never called 
@Override 
public void onCreateContextMenu(ContextMenu menu, View v, 
     ContextMenuInfo menuInfo) { 
    super.onCreateContextMenu(menu, v, menuInfo); 
    menu.add(0, DELETE_ID, 0, R.string.menu_delete); 
} 

@Override - this is never called 
public boolean onContextItemSelected(android.view.MenuItem item) { 
    switch (item.getItemId()) { 
    case DELETE_ID: 
     AdapterContextMenuInfo info = (AdapterContextMenuInfo) item 
       .getMenuInfo(); 
     Uri uri = Uri.parse(DatabaseContentProvider.CONTENT_URI + "/" 
       + info.id); 
     getActivity().getContentResolver().delete(uri, null, null); 
     return true; 
    } 
    return super.onContextItemSelected(item); 
} 

// Loader code 
// Creates a new loader after the initLoader() call 
@Override 
public Loader<Cursor> onCreateLoader(int id, Bundle args) { 
    String[] projection = { LocationsTable.KEY_ID, LocationsTable.LOCATION_NAME, LocationsTable.LOCATION_PHONE_NAME }; 
    CursorLoader cursorLoader = new CursorLoader(getActivity(), 
      DatabaseContentProvider.CONTENT_URI, projection, null, null, null); 
    return cursorLoader; 
} 

@Override 
public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 
    adapter.swapCursor(data); 
} 

@Override 
public void onLoaderReset(Loader<Cursor> loader) { 
    // data is not available anymore, delete reference 
    adapter.swapCursor(null); 
} 

} 

MISE À JOUR: J'ai toujours pas compris cela et je me demande si je dois renoncer à cette stratégie et la mettre en œuvre dans un autre, et non de manière conviviale. Peut-être un coup d'oeil pour voir les détails et un robinet pour supprimer?

Répondre

4

J'ai trouvé ma réponse dans le code source Android pour l'application Email native. https://android.googlesource.com/platform/packages/apps/Email/

Le ListFragment doit mettre en œuvre les auditeurs:

public class MessageListFragment extends SherlockListFragment 
    implements LoaderManager.LoaderCallbacks<Cursor>, AdapterView.OnItemLongClickListener 

    private static final int DELETE_ID = Menu.FIRST + 1;  

    private SimpleCursorAdapter adapter; 

    // The LoaderManager needs initializing 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 

     super.onCreate(savedInstanceState); 

     // Fields from the database (projection) 
     // Must include the _id column for the adapter to work 
     String[] from = new String[] { BookmarksTable.BOOKMARK_NAME, 
      BookmarksTable.BOOKMARK_PHONE_NAME }; 
     // Fields on the UI to which we map 
     int[] to = new int[] { R.id.titleText, R.id.phoneText }; 

     // connect to the database 
     getLoaderManager().initLoader(0, null, this); 
     adapter = new BookmarkCursorAdapter(getActivity(), 
      R.layout.bookmark_row, null, from, to, 0); 

     setListAdapter(adapter); 
    } 

    // register to put up the context menu 
    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
     Bundle savedInstanceState) { 
     View root = super.onCreateView(inflater, container, savedInstanceState); 
     registerForContextMenu(root); 
     return root; 
    } 

    // set the listeners for long click 
    @Override 
    public void onViewCreated(View view, Bundle savedInstanceState) { 
     super.onViewCreated(view, savedInstanceState); 
     getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE); 
     getListView().setOnItemLongClickListener(this); 
    } 

Les méthodes appelées sont:

/** 
    * Called when a message is clicked. 
    */ 
@Override 
public void onListItemClick(ListView parent, View view, int position, long id) { 
     // do item click stuff; show detailed view in my case 

} 


@Override 
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { 
    return false; // let the system show the context menu 
    } 

// Context menu 
@Override 
public void onCreateContextMenu(ContextMenu menu, View v, 
     ContextMenuInfo menuInfo) { 
    super.onCreateContextMenu(menu, v, menuInfo); 
    menu.add(0, DELETE_ID, 0, R.string.menu_delete); 
} 

    // respond to the context menu tap 
@Override 
public boolean onContextItemSelected(android.view.MenuItem item) { 
    switch (item.getItemId()) { 
    case DELETE_ID: 
     AdapterContextMenuInfo info = (AdapterContextMenuInfo) item 
       .getMenuInfo(); 
     Uri uri = Uri.parse(DatabaseContentProvider.BOOKMARK_ID_URI + Long.toString(info.id)); 
     getActivity().getContentResolver().delete(uri, null, null); 
     return true; 
    } 
    return super.onContextItemSelected(item); 
} 

Pour être complet, voici le code du chargeur

// Loader code 
// Creates a new loader after the initLoader() call 
@Override 
public Loader<Cursor> onCreateLoader(int id, Bundle args) { 
    String[] projection = { BookmarksTable.KEY_ID, BookmarksTable.BOOKMARK_NAME, BookmarksTable.BOOKMARK_PHONE_NAME }; 
    CursorLoader cursorLoader = new CursorLoader(getActivity(), 
      DatabaseContentProvider.BOOKMARKS_URI, projection, null, null, null); 
    return cursorLoader; 
} 

@Override 
public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 
    adapter.swapCursor(data); 
} 

@Override 
public void onLoaderReset(Loader<Cursor> loader) { 
    // data is not available anymore, delete reference 
    adapter.swapCursor(null); 
} 
Questions connexes