Contact List using ListView and SimpleCusrorAdapter with Contact Photos and Filter/Search
I had been looking for a simpler solution and my final solution is quite closer to the one Daniel mentioned here so I thought I should share mine here. I am using Fragment to show Device Contacts as a list of names with their pictures. Result is pretty similar to that of Daniel's but is showing only names. More information can be shown very easily once you understand the code.
In my case I was fetching names and pictures from ContactsContract using PHOTO_URI so I didn't have to extend SimpleCursorAdapter as Daniel had to.
My example also includes filtering the list of contacts as user types in SearchView to find a contact
I have a Fragment called FragmentContacts and two Layout files, first the main Layout frag_contacts.xml and second for each contact row list_row_contact.
frag_contacts.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <FrameLayout android:layout_width="fill_parent" android:layout_height="0dp" android:layout_weight="1" android:background="@android:color/holo_blue_light" android:padding="8dip"> <android.support.v7.widget.SearchView android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/white" android:id="@+id/searchView"/> </FrameLayout> <LinearLayout android:id="@+id/ll_contactList" android:layout_width="fill_parent" android:layout_height="0dp" android:layout_weight="9" android:orientation="vertical" > <ListView android:id="@+id/lv_ContactList" android:layout_width="fill_parent" android:layout_height="fill_parent" android:divider="#aaaaaa" android:dividerHeight="1dp" > </ListView> </LinearLayout> </LinearLayout>
list_row_contact.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" android:orientation="horizontal" android:descendantFocusability="blocksDescendants"> <FrameLayout android:layout_height="match_parent" android:layout_width="0dp" android:layout_weight="1" android:gravity="center"> <ImageView android:id="@+id/imgContact" android:layout_width="35dip" android:layout_height="35dip" android:layout_gravity="center" android:layout_margin="5dip" /> </FrameLayout> <TextView android:id="@+id/contact_name" android:layout_height="match_parent" android:layout_width="0dp" android:layout_weight="6" android:gravity="center_vertical" android:textSize="18sp" android:paddingLeft="10dip"> </TextView> </LinearLayout>
FragmentContacts.java
public class FragmentContacts extends Fragment implements LoaderManager.LoaderCallbacks<Cursor>{ private ListView lv_ContactList; private SearchView searchView; private SimpleCursorAdapter mCursorAdapter; private static final String DISPLAY_NAME = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? Contacts.DISPLAY_NAME_PRIMARY : Contacts.DISPLAY_NAME; private static final String[] contactsColumns = { Contacts._ID, Contacts.LOOKUP_KEY, DISPLAY_NAME, Contacts.PHOTO_URI }; private final String contactsFilter = "(" +Contacts.HAS_PHONE_NUMBER+ "='1') AND (" + Contacts.IN_VISIBLE_GROUP + "='1')"; private final String contactsSortOrder = DISPLAY_NAME + " COLLATE LOCALIZED ASC"; private final static String[] listDisplayColumns = { DISPLAY_NAME, Contacts.PHOTO_URI }; private final static int[] listDataViewIDs = { R.id.contact_name, R.id.imgContact }; String[] mSelectionArgs; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.frag_contacts, null); lv_ContactList = (ListView)view.findViewById(R.id.lv_ContactList); searchView = (SearchView)view.findViewById( R.id.searchView); return view; } @Override public void onResume(){ super.onResume(); mCursorAdapter= new SimpleCursorAdapter( getActivity(), R.layout.list_row_contact, null, listDisplayColumns, listDataViewIDs, 0); lv_ContactList.setAdapter(mCursorAdapter); getLoaderManager().initLoader(0, null, this); searchView.setOnQueryTextListener( new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit( String query ) {return false;} @Override public boolean onQueryTextChange( String newText ) { if( newText.isEmpty() ) mSelectionArgs = null; else mSelectionArgs = new String[]{ "%"+newText.trim()+"%"}; getLoaderManager().restartLoader( 0, null, FragmentContacts.this ); return false; } } ); } @Override public Loader<Cursor> onCreateLoader( int id, Bundle args ) { if(mSelectionArgs == null) return new CursorLoader( getActivity(), Contacts.CONTENT_URI, contactsColumns, contactsFilter, null, contactsSortOrder ); else return new CursorLoader( getActivity(), Contacts.CONTENT_URI, contactsColumns, contactsFilter + " AND (" + DISPLAY_NAME+" LIKE ?)", mSelectionArgs, contactsSortOrder ); } @Override public void onLoadFinished( Loader<Cursor> loader, Cursor data ) { mCursorAdapter.swapCursor(data); } @Override public void onLoaderReset( Loader<Cursor> loader ) { mCursorAdapter.swapCursor(null); } }