An Android ActionBar + ListFragment example
The source code below corresponds to an article I wrote titled, Android ActionBar example: How to create an options menu item.
package com.valleyprogramming.justbe;
import android.app.ListFragment;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.ListView;
import android.widget.TextView;
import com.valleyprogramming.justbe.QuotesDatabaseHelper.QuoteCursor;
import com.example.android.swipedismiss.SwipeDismissListViewTouchListener;
public class QuotesListFragment extends ListFragment {
private static final String TAG = "VPQuotesListFragment";
private QuoteCursor quoteCursor;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
getActivity().setTitle(R.string.title_quotes_screen);
// config the database and adapter
quoteCursor = DatabaseManager.get(getActivity()).queryQuotes();
// create an adapter to point at this cursor
QuoteCursorAdapter adapter = new QuoteCursorAdapter(getActivity(), quoteCursor);
setListAdapter(adapter);
}
@Override
public void onDestroy() {
quoteCursor.close();
//TODO working on possible memory leaks
quoteCursor = null;
setListAdapter(null);
super.onDestroy();
}
@Override
public void onActivityCreated(Bundle bundle) {
super.onActivityCreated(bundle);
// get a handle to our list view to implement 'swipe to delete'
ListView listView = getListView();
// Create a ListView-specific touch listener. ListViews are given special treatment because
// by default they handle touches for their list items... i.e. they're in charge of drawing
// the pressed state (the list selector), handling list item clicks, etc.
SwipeDismissListViewTouchListener touchListener =
new SwipeDismissListViewTouchListener(
listView,
new SwipeDismissListViewTouchListener.DismissCallbacks() {
@Override
public boolean canDismiss(int position) {
return true;
}
@Override
public void onDismiss(ListView listView, int[] reverseSortedPositions) {
for (int position : reverseSortedPositions) {
String quoteToDelete = ((QuoteCursor)(getListAdapter()).getItem(position)).getQuote().getQuote();
DatabaseManager.get(getActivity()).deleteQuote(quoteToDelete);
// need the next two lines to update the list after the delete
refreshQuoteCursorDataSet();
handleCasesWhereThisQuoteWasTheCurrentlyDisplayedQuote(quoteToDelete);
}
}
});
listView.setOnTouchListener(touchListener);
// setting this scroll listener is required to ensure that during ListView scrolling,
// we don't look for swipes.
listView.setOnScrollListener(touchListener.makeScrollListener());
}
private void handleCasesWhereThisQuoteWasTheCurrentlyDisplayedQuote(String quoteThatWasDeleted) {
if (GlobalState.currentlyDisplayedQuote.equals(quoteThatWasDeleted)) {
if (GlobalState.pinnedStateEnabled) {
// the quote that was deleted was the current quote and it was pinned
PreferencesUtils.handleUserUnpinsQuoteAction(getActivity().getBaseContext());
GlobalState.currentlyDisplayedQuote = "";
} else {
// the quote that was deleted was the current quote but it was not pinned
GlobalState.currentlyDisplayedQuote = "";
}
}
}
/**
* When a list item is clicked, perform the 'Edit' action.
*/
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
String quote = ((QuoteCursor)(getListAdapter()).getItem(position)).getQuote().getQuote();
Log.d(TAG, quote + " was clicked");
// i'm doing this in the long form just for my own knowledge
Context context = getActivity();
Class destination = EditQuoteActivity.class;
Intent intent = new Intent(context, destination);
intent.putExtra(EditQuoteFragment.KEY_QUOTE_EXTRA, quote);
startActivityForResult(intent, 0);
}
/**
* update the list of quotes when the user returns, presumably after
* using the 'edit' screen. p. 197.
*
* the book's code example actually uses onActivityResult instead of
* onResume. i just tested it, and they both get called, so either one
* will work.
*/
@Override
public void onResume() {
super.onResume();
refreshQuoteCursorDataSet();
}
/**
* as the code shows, the cursor needs to be refreshed before
* notifyDataSetChanged is called
*/
private void refreshQuoteCursorDataSet() {
quoteCursor.requery();
((QuoteCursorAdapter)getListAdapter()).notifyDataSetChanged();
}
/**
* the menu layout has the 'add/new' menu item
*/
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
menuInflater.inflate(R.menu.menu_quotes_list, menu);
super.onCreateOptionsMenu(menu, menuInflater);
}
/**
* react to the user tapping/selecting an options menu item
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_item_new_quote:
Intent addQuoteIntent = new Intent(getActivity(), NewQuoteActivity.class);
startActivityForResult(addQuoteIntent, 0);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
/**
* The adapter class that will work with the ListView.
*/
private static class QuoteCursorAdapter extends CursorAdapter {
private QuoteCursor mRunCursor;
public QuoteCursorAdapter(Context context, QuoteCursor cursor) {
super(context, cursor, 0);
mRunCursor = cursor;
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
return inflater.inflate(R.layout.quote_item_view, parent, false);
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
// get the quote for the current row
Quote quote = mRunCursor.getQuote();
// this works with my custom view (quote_item_view.xml)
TextView textView = (TextView)view.findViewById(R.id.the_quote);
textView.setText(quote.getQuote());
// set the text size
textView.setTextAppearance(context, R.style.listViewText);
// confirmed: this works. can also specify alpha as '00-ff' before the rgb
// component, but that won't do anything in this case
textView.setBackgroundColor(Color.parseColor("#ffffff"));
}
}
}
The reason I show the code here is because it shows how to enable the Android ActionBar, in this case from a Fragment, and more specifically a ListFragment.