Hello Readers
I have been making progress on my summarizer app lately. During these past couple of days I implemented a feature which lets the user swipe views as an alternative to having to tap on the tabs. This makes it more easy to swap between tabs.
Here’s How You Can Do It Too
If you’re like me, explaining something complex is facilitated by using metaphors. So I am going to do my best to explain this by making use of them.
Note: The code I use in this tutorial can be found at developer.android. But since the explanation there is kind of dry, I will try to expand on it with my own words.
ViewPager – The Book
let’s talk about a ViewPager, one of the elements you will need in order to create swipe views. A ViewPager is like a Book. A book is nice, right? It consists of pages, which have lots of information in them. So just keep that in mind, A ViewPager is like a book.
What is it really though? A ViewPager is a layout manager. It allows users to flip pages, which in our case are sub-activities appearing under each tab.
Let’s start by defining one in XML, create a new android XML file, name it “activity_collection_demo” and paste the following code in it:
<?xml version="1.0" encoding="utf-8"?> <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" />
This will be the layout used in the activity in which you want to implement your swipe views.
PagerAdapter – The Book Manager
Imagine the PagerAdapter as a person who inserts pages into a book. Without him, you would just have the book cover. He also handles in what order the pages are going to be in.
PagerAdapter is an abstract class, so we need to use one of its childs. In this case we are using FragmentStatePagerAdapter.
Fragment- The Page
We have a book, we have the person inserting pages and managing them. We just need the actual pages. Fragments are our pages. Remember how I said “sub-activities under each tab” earlier on? The correct word is fragment.
You can see it this way: A fragment is a sub-activity, usually one under each tab if there are tabs in the activity. So if you have 4 tabs in one activity, you have 4 fragments in that activity. I guess they chose to call them fragments because they are just a fragment, as in a part of an activity.
You should define an Android XML layout for each fragment, just as how you define a layout for an activity. You can also have multiple fragments using the same layout. So go ahead and define the ones you need.
Combining Everything
Now that you have the book, the book manager and the pages let me show how to combine them. The tabs are going to be added later on.
You will use three clasess, I will try to explain (remember I’m no expert at this) almost line by line so I will take one class at a time and talk about it.
public class CollectionDemoActivity extends FragmentActivity { // When requested, this adapter returns a DemoObjectFragment, // representing an object in the collection. DemoCollectionPagerAdapter mDemoCollectionPagerAdapter; ViewPager mViewPager; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_collection_demo); // ViewPager and its adapters use support library // fragments, so use getSupportFragmentManager. mDemoCollectionPagerAdapter = new DemoCollectionPagerAdapter( getSupportFragmentManager()); mViewPager = (ViewPager) findViewById(R.id.pager); mViewPager.setAdapter(mDemoCollectionPagerAdapter); } }
Here we are creating a class called CollectionDemoActivity, which extends a FragmentActivity. “collection” refers to a collection of fragments. You need to inherit FragmentActivity to be able to use fragments. And yes, you do need them, remember they are the pages, without them there is no shiny swiping!
Next up we define an object called mDemoCollectionPagerAdapter. This is a self made class which I will talk about later. Then we also define an object called mViewPager from the class ViewPager, you already know what this object does.
We move on to the onCreate() method of the activity. First thing we do is set the content view to the activity layout that we defined earlier on. This layout serves to tell the system that it has a viewpager. Second, we instantiate both the DemoCollectionPagerAdapter (and pass a fragmentmanager object as arguement) and the Viewpager. Lastly, we call the setAdapter method from the mViewPager object, and pass the mDemoCollectionPagerAdapter object as an arguement. This is saying that your viewpager object is going to have the mDemoCollectionPagerAdapter as it’s adapter. In other words, the book is assigning a book manager to handle his pages.
The fragmentmanager we passed as an arguement to the pageradapter is an object that belongs to the FragmentActivity class. Since we are extending our class to a FragmentActivity, we can make use of FragmentManager.
Let’s move on.
public class DemoCollectionPagerAdapter extends FragmentStatePagerAdapter { public DemoCollectionPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int i) { Fragment fragment = new DemoObjectFragment(); Bundle args = new Bundle(); // Our object is just an integer :-P args.putInt(DemoObjectFragment.ARG_OBJECT, i + 1); fragment.setArguments(args); return fragment; } @Override public int getCount() { return 3; } @Override public CharSequence getPageTitle(int position) { return "OBJECT " + (position + 1); } }
This public class DemoCollectionPagerAdapter extends the FragmentStatePagerAdapter class. You have to implement your own class as FragmentStatePagerAdapater is abstract. You can name it what you want, it represents the The Book Manager (PagerAdapter).
The first method just passes the fragmentmanager on to its superclass.
The second method, getItem, gets the fragment (the page) that you want. This is done by first instantiating the fragment object from another nested class we will define later on. Next an integer is added as an arguement to the fragment, what this will do is show the number of the fragment. Imagine there’s 10 fragments in your activity, then when choosing tab number 8, that number will appear once you call that fragment.
The third method, getCount, just returns the number of fragments that the activity has. This is where you choose how many fragments you want.
The fourth method is just an automatic title creator for each fragment on your activity. For example the title for the 4th fragment would be OBJECT 4.
Moving on.
// Instances of this class are fragments representing a single // object in our collection. public static class DemoObjectFragment extends Fragment { public static final String ARG_OBJECT = "object"; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // The last two arguments ensure LayoutParams are inflated // properly. View rootView = inflater.inflate( R.layout.fragment_collection_object, container, false); Bundle args = getArguments(); ((TextView) rootView.findViewById(android.R.id.text1)).setText( Integer.toString(args.getInt(ARG_OBJECT))); return rootView; } }
This class represents the Pages, or the Fragments. Again, you can call it what you want, but it must extend the Fragment class, which is also an abstract class.
This fragment object only has one method which does a couple of things. First, it inflates a layout, which you can define to look however you want and stores it in a view called rootView. Second, it gets a textview via rootView and sets its text to the number of the fragment. This number is sent through the arguments (ARG_OBJECT) we defined earlier in DemoCollectionPagerAdapter. Lastly, it returns rootView.
Note: Right now we just defined one fragment, this means that it doesn’t matter how many fragments your activity has, it can only implement the one fragment we defined. to add more fragments and use different layouts, just create another class and extend Fragment, and assign a different layout to it.
That’s how you combine the three players: The Book, The Book Manager and The Page. But we are not finished yet, we are missing the tabs and also the whole purpose of this tutorial: the swiping!
Implementing Tabs and Swiping to our Demo
Let’s jump into the code for adding tabs first:
@Override public void onCreate(Bundle savedInstanceState) { final ActionBar actionBar = getActionBar(); ... // Specify that tabs should be displayed in the action bar. actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); // Create a tab listener that is called when the user changes tabs. ActionBar.TabListener tabListener = new ActionBar.TabListener() { public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) { // When the tab is selected, switch to the // corresponding page in the ViewPager. mViewPager.setCurrentItem(tab.getPosition()); } public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) { // hide the given tab } public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) { // probably ignore this event } }; // Add tabs, specifying the tab's text and TabListener for (int i = 0; i < mDemoCollectionPagerAdapter.getCount(); i++) { actionBar.addTab( actionBar.newTab() .setText(mDemoCollectionPagerAdapter.getPageTitle(i)) .setTabListener(tabListener)); } mViewPager.setOnPageChangeListener( new ViewPager.SimpleOnPageChangeListener() { @Override public void onPageSelected(int position) { // When swiping between pages, select the // corresponding tab. getActionBar().setSelectedNavigationItem(position); } }); }
This code goes inside the onCreate() method of the first class we created: CollectionDemoActivity.
First we get the activities’ actionbar by calling getActionBar() and assign that to the variable actionBar.
By calling the method setNavigationMode and passing NAVIGATION_MODE_TAB we are telling the system that we are going to use tabs in order to navigate through our activity.
Next, we create a tab listener which then implements three methods. They listen to whenever the user selects, reselects or unselects a tab. Add code accordingly if you want something to happen when navigating through tabs. In the code shown above, whenever the user selects a tab, we tell the viewpager (the book) to show a specific fragment with the method setCurrentItem(tab.getPosition()).
Note: This tab listener doesn’t listen to swipes. We are going to create another listener that will listen to swipes in a few moments.
We then create three tabs. We iterate until mDemoCollectionPagerAdapter.getCount() because that’s where we know how many tabs we want. Inside each iteration we define the page title by calling the getPageTitle() method. Finally, we set the listener to the tabs we created. If you use “this” instead of “tabListener” then your activity will implement the ActionBar.TabListener interface instead of the object tabListener that we just defined.
Last of all, and most important of all, because this is what we were waiting for, is the swipe listener. It’s called a SimpleOnPageListener and it does what it says, listen to the “pages” (fragments). We start by getting our mViewPager object and calling setOnPageChangeListener. As an arguement we implement the SimpleOnPageListener interface and override its onPageSelected method to call setNavigationItem() and set the specific tab that we want whenever we swipe.
And that does it, with that listener in place, you will be able to swipe between your fragments.
Closing
I have shown you how to implement the swipe feature by using the code found on developer.android. It was really hard to read through that page because of the lack of explanation, so I hope that by writing this I cleared out some of your doubts.
If you tried to implement this and it didn’t work, don’t hesitate to ask me. What I did to implement this feature was follow the various tutorials out there by other people like me.
Note: If you see something wrong, please do comment so I can correct it!
It would be great if you tried out the app where I implemented swipe views and told me what you think!
Link to App: Click Here
If you like, you can sign up to my mailing list and receive an e-mail notification whenever I bring out new content. No spam! I promise :)
[wp_email_capture_form]
Leave a Reply