Build your first pro Android application with Eclipse
DownloadKeywords: AppCompat Fragment ActionBar ViewPager Navigation Drawer LoaderManager SQLiteDatabase CursorLoader SimpleCursorAdapter ContentProvider SQLiteOpenHelper ContentResolver ListFragment ListView GridView DialogFragment Volley Library RequestQueue ImageLoader NetworkImageView
Contents- Overview
- Create a new Eclipse Android project
- Add Android Support library
- Android manifest
- Application theme
- Application class
- Splash screen
- Login screen
- Help screen
- Settings screen
- Navigation Drawer
- Main screen
- Dialog Fragment
- Content Provider
- Data model
- List Fragment
- Data Adapter
- Grid View
- View Pager
- Detail screen
- Volley Library
- What's next?
19. View Pager
ViewPager is available in Android support library that allows user to flip left and right through pages of data.Let's first see how to add ViewPager to the layout file fragment_item_pager.xml.
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/pager" android:layout_width="match_parent" android:layout_height="match_parent" />Fundamentally, view pager implementation is similar to list view or grid view.
public class ItemPagerFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> { /** * The pager widget, which handles animation and allows swiping horizontally to access previous * and next wizard steps. */ private ViewPager mPager; /** * The pager adapter, which provides the pages to the view pager widget. */ private CursorPagerAdapter adapter; public ItemPagerFragment() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment View rootView = inflater.inflate(R.layout.fragment_item_pager, container, false); // Instantiate a ViewPager and a PagerAdapter. mPager = (ViewPager) rootView.findViewById(R.id.pager); adapter = new CursorPagerAdapter(getFragmentManager(), null); mPager.setAdapter(adapter); getLoaderManager().initLoader(0, null, this); return rootView; } @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { CursorLoader loader = new CursorLoader(getActivity(), DataProvider.CONTENT_URI_DATA, new String[]{DataProvider.COL_ID}, null, null, null); return loader; } @Override public void onLoadFinished(Loader<Cursor> loader, Cursor data) { adapter.swapCursor(data); } @Override public void onLoaderReset(Loader<Cursor> loader) { adapter.swapCursor(null); } }We create a custom adapter for view pager and populate it through Loader. Create a nested class inside ItemPagerFragment to implement a custom FragmentStatePagerAdapter.
/** * A simple pager adapter. */ private class CursorPagerAdapter extends FragmentStatePagerAdapter { private Cursor mCursor; public CursorPagerAdapter(FragmentManager fm, Cursor c) { super(fm); mCursor = c; } @Override public Fragment getItem(int position) { if (mCursor.moveToPosition(position)) { Bundle arguments = new Bundle(); arguments.putLong(ItemDetailFragment.ARG_ITEM_ID, mCursor.getLong(mCursor.getColumnIndex(DataProvider.COL_ID))); ItemDetailFragment fragment = new ItemDetailFragment(); fragment.setArguments(arguments); return fragment; } return null; } @Override public int getCount() { if (mCursor != null) { return mCursor.getCount(); } return 0; } public void swapCursor(Cursor cursor) { mCursor = cursor; notifyDataSetChanged(); } }Each item in adapter is a fragment. So we create ItemDetailFragment class to provide implementation for a page. The major chunk of code is inside onCreateView() method to populate the views with data from cursor.
public class ItemDetailFragment extends Fragment { /** * The fragment argument representing the item ID that this fragment * represents. */ public static final String ARG_ITEM_ID = "item_id"; private long id; /** * Mandatory empty constructor for the fragment manager to instantiate the * fragment (e.g. upon screen orientation changes). */ public ItemDetailFragment() { } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getArguments().containsKey(ARG_ITEM_ID)) { // Load the dummy content specified by the fragment // arguments. In a real-world scenario, use a Loader // to load content from a content provider. id = getArguments().getLong(ARG_ITEM_ID); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_item_detail, container, false); // Show the dummy content as text in a TextView. if (id > 0) { Uri contentUri = ContentUris.withAppendedId(DataProvider.CONTENT_URI_DATA, id); Cursor c = getActivity().getContentResolver().query(contentUri, null, null, null, null); if (c != null) { if (c.moveToFirst()) { String content = c.getString(c.getColumnIndex(DataProvider.COL_CONTENT)); Data data = new Data(content); String title = data.getTitle(); String desc = data.getDescription(); String iconUrl = data.getIcon(); String downloadUrl = data.getDownloadUrl(); String tutorialUrl = data.getTutorialUrl(); ((TextView) rootView.findViewById(R.id.textView1)).setText(title); ((TextView) rootView.findViewById(R.id.item_detail)).setText(desc); NetworkImageView iconView = (NetworkImageView) rootView.findViewById(R.id.imageView1); iconView.setDefaultImageResId(R.drawable.ic_launcher); iconView.setImageUrl(iconUrl, App.getInstance().getImageLoader()); if (!TextUtils.isEmpty(downloadUrl)) { TextView downloadLink = (TextView) rootView.findViewById(R.id.downloadLink); downloadLink.setMovementMethod(LinkMovementMethod.getInstance()); downloadLink.setText(Html.fromHtml("<a href='"+downloadUrl+"'>Download</a>")); } if (!TextUtils.isEmpty(tutorialUrl)) { TextView tutorialLink = (TextView) rootView.findViewById(R.id.tutorialLink); tutorialLink.setMovementMethod(LinkMovementMethod.getInstance()); tutorialLink.setText(Html.fromHtml("<a href='"+tutorialUrl+"'>Read tutorial</a>")); } } c.close(); } } return rootView; } }We'll reuse this fragment in the next section for implementing detail screen.
20. Detail screen
Detail screen is implemented using an activity that inherits from ActionBarActivity available in Android v7 appcompat library. ActionBarActivity provides action bar to the screen.Let's first create an activity with help of Eclipse wizard. Go to File > New > Other... and select Android Activity under Android. Click Next and select Blank Activity. Click Next. Enter activity name as DetailActivity and specify Hierarchical Parent as MainActivity. Click Finish. The activity class and layout gets generated as well as the manifest is updated.
public class DetailActivity extends ActionBarActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_detail); // Show the Up button in the action bar. setupActionBar(); if (savedInstanceState == null) { // Create the detail fragment and add it to the activity // using a fragment transaction. Bundle arguments = new Bundle(); arguments.putLong(ItemDetailFragment.ARG_ITEM_ID, getIntent().getLongExtra(ItemDetailFragment.ARG_ITEM_ID, -1)); ItemDetailFragment fragment = new ItemDetailFragment(); fragment.setArguments(arguments); getSupportFragmentManager().beginTransaction().add(R.id.item_detail_container, fragment).commit(); } } /** * Set up the {@link android.app.ActionBar}, if the API is available. */ @TargetApi(Build.VERSION_CODES.HONEYCOMB) private void setupActionBar() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { getActionBar().setDisplayHomeAsUpEnabled(true); } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.detail, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: NavUtils.navigateUpFromSameTask(this); return true; case R.id.action_delete: long id = getIntent().getLongExtra(ItemDetailFragment.ARG_ITEM_ID, -1); if(id != -1) { getContentResolver().delete(ContentUris.withAppendedId(DataProvider.CONTENT_URI_DATA, id), null, null); finish(); } return true; } return super.onOptionsItemSelected(item); } }Most of the code was generated by the wizard including code for handling up navigation in onOptionsItemSelected() method. However, we modified onCreate() method to display ItemDetailFragment, and onOptionsItemSelected() method to add delete functionality.
For adding delete item menu option to the screen you'll need to modify the generated detail.xml file under res/menu directory as follows.
<menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:myapp="http://schemas.android.com/apk/res-auto" > <item android:id="@+id/action_delete" android:showAsAction="always" myapp:showAsAction="always" android:icon="@android:drawable/ic_menu_delete" android:title="@string/action_delete"/> </menu>Finally, let's take a look at the activity_detail.xml layout file for this activity.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/item_detail_container" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".DetailActivity" tools:ignore="MergeRootFrame" />Since we are using a fragment i.e. ItemDetailFragment for displaying content hence the layout is simply a place holder. Recall that we added the fragment using fragment transaction in onCreate() method of DetailActivity.