{"id":1777,"date":"2014-10-11T22:49:44","date_gmt":"2014-10-11T17:19:44","guid":{"rendered":"http:\/\/codetheory.in\/?p=1777"},"modified":"2016-07-11T22:30:58","modified_gmt":"2016-07-11T17:00:58","slug":"android-swipe-views-with-tabs","status":"publish","type":"post","link":"https:\/\/codetheory.in\/android-swipe-views-with-tabs\/","title":{"rendered":"Android Swipe (Touch Gesture) Views Using ViewPager, FragmentPagerAdapter and FragmentStatePagerAdapter With Action Bar Tabs"},"content":{"rendered":"
Swipe Views<\/a> are an efficient way to allow the user to laterally navigate among related data items spread across multiple panes using a simple touch gesture (swipes\/flings), making access to data faster and much more enjoyable. Think of the android home screen where you can swipe across multiple sibling screens or the facebook or twitter app with multiple screens (and their respective tabs) where you can just swipe to navigate through them. The entire experience is super interactive and fun. They’re basically equivalent to slideshows\/carousels which has sections with\/without tabs (or similar controls to navigate) in the web development arena.<\/p>\n <\/p>\n Android provides us with the Once this code is placed in say Let’s see how our Activity class will look like where we’ll get the Here’s our The What we basically do in the The Pretty simple! All you need to do now is test your app and play with the Tip:<\/strong> At times you might have multiple fragments that you’ll want to return in the … and all of them having different layout resources that’d display different sorts of data like photo gallery, activity feed, list of messages, etc.<\/p>\n I think I’ve already explained why this In order to understand how to work with it, all you need to do is use the previous example and instead of making the By now you’ll know the differences between FragmentPagerAdapter<\/a> and FragmentStatePagerAdapter<\/a> and which one to use when.<\/p>\n Along with having our swiping views there has to be something that hints the user that he can swipe through for a much better user experience. Tabs can do a great job for that purpose and in Android we can use the Next, we’ll have to add the tabs, specify their text and add various listeners for them.<\/p>\n Pretty straightforward piece of code. Notice the part where we set the tab listener using Super simple and easy! When a tab is selected, we show the respective screen in our Instead of creating this Likewise, when the user changes the screen inside the So the entire If for some reason you don’t want to include tabs in the action bar but have it in the So we covered quite a bit in this tutorial. We learnt how to create a swipeable UI element with multiple screens using It’s quite interesting to note that If you have any questions or want to discuss something regarding this topic, then feel free to comment below.<\/p>\n","protected":false},"excerpt":{"rendered":" Swipe Views are an efficient way to allow the user to laterally navigate among related data items spread across multiple panes using a simple touch gesture (swipes\/flings), making access to data faster and much more enjoyable. Think of the android home screen where you can swipe across multiple sibling screens or the facebook or twitter … Continue reading “Android Swipe (Touch Gesture) Views Using ViewPager, FragmentPagerAdapter and FragmentStatePagerAdapter With Action Bar Tabs”<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[121],"tags":[105,128,89],"_links":{"self":[{"href":"https:\/\/codetheory.in\/wp-json\/wp\/v2\/posts\/1777"}],"collection":[{"href":"https:\/\/codetheory.in\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/codetheory.in\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/codetheory.in\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/codetheory.in\/wp-json\/wp\/v2\/comments?post=1777"}],"version-history":[{"count":8,"href":"https:\/\/codetheory.in\/wp-json\/wp\/v2\/posts\/1777\/revisions"}],"predecessor-version":[{"id":2500,"href":"https:\/\/codetheory.in\/wp-json\/wp\/v2\/posts\/1777\/revisions\/2500"}],"wp:attachment":[{"href":"https:\/\/codetheory.in\/wp-json\/wp\/v2\/media?parent=1777"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/codetheory.in\/wp-json\/wp\/v2\/categories?post=1777"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/codetheory.in\/wp-json\/wp\/v2\/tags?post=1777"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}ViewPager<\/code><\/a> class that allows the user to flip left and right through pages of data. To use it, you’ll have to put the
<ViewPager><\/code> element (from the support library<\/a>) inside your XML layout file that’ll contain multiple child views (which will be the different pages). This is how it’s done:<\/p>\n
\r\n<android.support.v4.view.ViewPager xmlns:android="http:\/\/schemas.android.com\/apk\/res\/android"\r\n android:id="@+id\/pager"\r\n android:layout_width="match_parent"\r\n android:layout_height="match_parent" \/>\r\n<\/pre>\n
res\/layout\/activity_main.xml<\/code>, we’ll have to hook the layout to a
PagerAdapter<\/code><\/a> which will populate our
ViewPager<\/code> with pages. Basically a
PagerAdapter<\/code> is responsible for creating the content for each page. You’ll most likely want to use one of the following two implementation of
PagerAdapter<\/code>:<\/p>\n
\n
FragmentPagerAdapter<\/code><\/a> – Each page is a fragment and all of them are kept in memory, hence best to use when there’s a fixed small set of screens to be navigated through. If loads of fragments are shoved in using this adapter then it could lead to a laggy user experience. It works even better when the content of the fragments are static than something that constantly changes or gets updated.\n<\/li>\n
FragmentStatePagerAdapter<\/code><\/a> – Each page is a fragment which gets destroyed as soon as it’s not visible to the user, i.e., the user navigates to another one. Due to this behaviour it consumes much less memory but then doesn’t perform as well as its counterpart (
FragmentPagerAdapter<\/code>). Hence, it’s perfect in the cases where the number of pages is high or undetermined.\n<\/li>\n<\/ul>\n
FragmentPagerAdapter<\/h2>\n
ViewPager<\/code> and hook a
FragmentPagerAdapter<\/code> to it.<\/p>\n
\r\npublic class MainActivity extends Activity {\r\n\r\n CustomPagerAdapter mCustomPagerAdapter;\r\n ViewPager mViewPager;\r\n\r\n @Override\r\n protected void onCreate(Bundle savedInstanceState) {\r\n super.onCreate(savedInstanceState);\r\n setContentView(R.layout.activity_main);\r\n\r\n \/\/ == Setting up the ViewPager ==\r\n\r\n mCustomPagerAdapter = new CustomPagerAdapter(getFragmentManager(), this);\r\n\r\n mViewPager = (ViewPager) findViewById(R.id.pager);\r\n mViewPager.setAdapter(mCustomPagerAdapter);\r\n }\r\n}\r\n<\/pre>\n
CustomPagerAdapter<\/code> which is a
FragmentPagerAdapter<\/code> implementation:<\/p>\n
\r\npublic class CustomPagerAdapter extends FragmentPagerAdapter {\r\n\r\n protected Context mContext;\r\n\r\n public CustomPagerAdapter(FragmentManager fm, Context context) {\r\n super(fm);\r\n mContext = context;\r\n }\r\n\r\n @Override\r\n \/\/ This method returns the fragment associated with\r\n \/\/ the specified position.\r\n \/\/\r\n \/\/ It is called when the Adapter needs a fragment\r\n \/\/ and it does not exists.\r\n public Fragment getItem(int position) {\r\n\r\n \/\/ Create fragment object\r\n Fragment fragment = new DemoFragment();\r\n\r\n \/\/ Attach some data to it that we'll\r\n \/\/ use to populate our fragment layouts\r\n Bundle args = new Bundle();\r\n args.putInt("page_position", position + 1);\r\n\r\n \/\/ Set the arguments on the fragment\r\n \/\/ that will be fetched in DemoFragment@onCreateView\r\n fragment.setArguments(args);\r\n\r\n return fragment;\r\n }\r\n\r\n @Override\r\n public int getCount() {\r\n return 3;\r\n }\r\n \r\n}\r\n<\/pre>\n
getCount()<\/code><\/a> method specifies how many views to show in the
ViewPager<\/code> and
getItem()<\/code><\/a> generates the views at the specified positions (passed in as an argument).<\/p>\n
getItem()<\/code> method is instantiate our Fragment and pass it some arguments data that’ll get used in the fragment’s (
DemoFragment<\/code>)
onCreateView()<\/code> method to populate its XML layout. Here’s how our Fragment class will look like:<\/p>\n
\r\npublic class DemoFragment extends Fragment {\r\n\r\n @Override\r\n public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\r\n \/\/ Inflate the layout resource that'll be returned\r\n View rootView = inflater.inflate(R.layout.fragment_demo, container, false);\r\n\r\n \/\/ Get the arguments that was supplied when\r\n \/\/ the fragment was instantiated in the\r\n \/\/ CustomPagerAdapter\r\n Bundle args = getArguments();\r\n ((TextView) rootView.findViewById(R.id.text)).setText("Page " + args.getInt("page_position"));\r\n\r\n return rootView;\r\n }\r\n}\r\n<\/pre>\n
onCreateView()<\/code><\/a> method is the one that inflates the layout resource and hence instantiates the user interface for that fragment. Here’s how our
res\/layout\/fragment_demo.xml<\/code> will look like:<\/p>\n
\r\n<FrameLayout xmlns:android="http:\/\/schemas.android.com\/apk\/res\/android"\r\n xmlns:tools="http:\/\/schemas.android.com\/tools"\r\n android:layout_width="match_parent"\r\n android:layout_height="match_parent">\r\n\r\n <TextView\r\n android:layout_width="match_parent"\r\n android:layout_height="match_parent"\r\n android:text="Page 0"\r\n android:id="@+id\/text" \/>\r\n\r\n<\/FrameLayout>\r\n<\/pre>\n
ViewPager<\/code> by swiping the different screens\/pages in it. They should display “Page 1”, “Page 2” and “Page 3” as texts.<\/p>\n
getItem()<\/code> method of the
FragmentPagerAdapter<\/code> implementation. Then you could do something like this:<\/p>\n
\r\nswitch (position) {\r\n case 0:\r\n return new FirstFragment();\r\n case 1:\r\n return new SecondFragment();\r\n case 2:\r\n return new ThirdFragment();\r\n}\r\n<\/pre>\n
FragmentStatePagerAdapter<\/h2>\n
PagerAdapter<\/code> is useful and when it should be used. Its main advantage is low memory consumption due to the destruction of fragments as soon as they go off the screen. So as soon as the user navigates to a particular screen the one next to it is generated\/rebuilt by calling
getItem()<\/code> in the adapter implementation. When the number of the pages are undetermined or are too many (for example in a book reader) then this adapter makes more sense than the previous one explained.<\/p>\n
CustomPagerAdapter<\/code> extend
FragmentPagerAdapter<\/code>, make it subclass
FragmentStatePagerAdapter<\/code>. Then in
getItem()<\/code> you could add a
Log.d()<\/code> to see when its called while swiping through the views inside the view pager.<\/p>\n
Adding Tabs to Action Bar<\/h2>\n
ActionBar<\/code><\/a> to quickly create them and integrate with our
ViewPager<\/code> making them work in conjunction. To specify that tabs should be displayed in the action bar we’ll have to set the navigation mode on the action bar object in
onCreate()<\/code> method like this:<\/p>\n
\r\nfinal ActionBar actionBar = getActionBar();\r\n\/\/ specify that action bar should display tabs\r\nactionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);\r\n<\/pre>\n
\r\n\/\/ == Setting up the tabs ==\r\n\r\nString[] tabs = {\r\n "Tab One", "Tab Two", "Tab Three"\r\n};\r\nActionBar.Tab tab;\r\nfor (int i = 0; i < tabs.length; i++) {\r\n tab = actionBar\r\n .newTab() \/\/ create new tab\r\n .setText(tabs[i]) \/\/ set text\r\n .setTabListener(tabListener); \/\/ set tab listeners\r\n \r\n \/\/ add the tab to the action bar finally\r\n actionBar.addTab(tab);\r\n}\r\n<\/pre>\n
setTabListener(tabListener)<\/code>. It’s time to define the
tabListener<\/code> object now, whose methods will be called whenever the user changes tabs.<\/p>\n
\r\nActionBar.TabListener tabListener = new ActionBar.TabListener() {\r\n @Override\r\n public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {\r\n \/\/ show the tab\r\n\r\n int position = tab.getPosition();\r\n mViewPager.setCurrentItem(position);\r\n }\r\n\r\n @Override\r\n public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {\r\n \/\/ hide the tab, we don't need this in this example\r\n }\r\n\r\n @Override\r\n public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {\r\n \/\/ when tab is reselected, we don't really need this\r\n }\r\n};\r\n<\/pre>\n
ViewPager<\/code> by calling its
setCurrentItem()<\/code><\/a> method.<\/p>\n
tabListener<\/code> object inside the
onCreate()<\/code> method we could have also made our Activity class implement
ActionBar.TabListener<\/code><\/a> and then overriden the methods as our activity class’s methods. The only change then required would be to modify
setTabListener(tabListener)<\/code> to
setTabListener(this)<\/code>.<\/p>\n
ViewPager<\/code> with a swipe touch gesture, we should select the corresponding tab. We can do this with the help of
ViewPager.OnPageChangeListener<\/code><\/a> interface or the
ViewPager.SimpleOnPageChangeListener<\/code><\/a> class. We’ll use the latter in this case so that we don’t have to override all the methods from the interface since when we won’t be using most of them.<\/p>\n
\r\n\/\/ When swiping between different sections, select the corresponding tab\r\nmViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {\r\n @Override\r\n public void onPageSelected(int position) {\r\n actionBar.setSelectedNavigationItem(position);\r\n }\r\n});\r\n<\/pre>\n
onCreate()<\/code> method will somewhat look like this:<\/p>\n
\r\nCustomPagerAdapter mCustomPagerAdapter;\r\nViewPager mViewPager;\r\n\r\n@Override\r\nprotected void onCreate(Bundle savedInstanceState) {\r\n super.onCreate(savedInstanceState);\r\n setContentView(R.layout.activity_main);\r\n\r\n \/\/ Setup the action bar for tabs\r\n final ActionBar actionBar = getActionBar();\r\n actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);\r\n actionBar.setTitle("App Title"); \/\/ If you want to set an app title\r\n\r\n \/\/ == Setting up the ViewPager ==\r\n\r\n mCustomPagerAdapter = new CustomPagerAdapter(getFragmentManager(), this);\r\n\r\n mViewPager = (ViewPager) findViewById(R.id.pager);\r\n mViewPager.setAdapter(mCustomPagerAdapter);\r\n\r\n \/\/ When swiping between different sections, select the corresponding tab\r\n mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {\r\n @Override\r\n public void onPageSelected(int position) {\r\n actionBar.setSelectedNavigationItem(position);\r\n }\r\n });\r\n\r\n\r\n \/\/ == Setting up the tabs ==\r\n\r\n ActionBar.TabListener tabListener = new ActionBar.TabListener() {\r\n @Override\r\n public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {\r\n \/\/ show the tab\r\n\r\n int position = tab.getPosition();\r\n mViewPager.setCurrentItem(position);\r\n }\r\n\r\n @Override\r\n public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {\r\n \/\/ hide the tab, we don't need this in this example\r\n }\r\n\r\n @Override\r\n public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {\r\n \/\/ when tab is reselected, we don't really need this\r\n }\r\n };\r\n\r\n String[] tabs = {\r\n "Tab One", "Tab Two", "Tab Three"\r\n };\r\n ActionBar.Tab tab;\r\n for (int i = 0; i < tabs.length; i++) {\r\n tab = actionBar\r\n .newTab() \/\/ create new tab\r\n .setText(tabs[i]) \/\/ set text\r\n .setTabListener(tabListener); \/\/ set tab listener\r\n actionBar.addTab(tab);\r\n }\r\n}\r\n<\/pre>\n
ViewPager<\/code> itself as scrollable tabs<\/a> then we can make use of
PagerTitleStrip<\/code><\/a> or
PagerTabStrip<\/code><\/a> that we’ll cover in another tutorial.<\/p>\n
Conclusion<\/h2>\n
ViewPager<\/code> and injecting the screens\/pages into it through
PagerAdapter<\/code> implementations like
FragmentPagerAdapter<\/code> and
FragmentStatePagerAdapter<\/code>. We also saw how we can integrate tabs to the entire Activity in the action bar that works in correspondence with the
ViewPager<\/code>.<\/p>\n
ViewPager<\/code> is not only restricted to be used with fragments but can be used with any other View like
ImageView<\/code> to create an image based slideshow. In that case the custom pager adapter implementation has to be of
PagerAdapter<\/code><\/a> directly. We’ll see how to do this in another post.<\/p>\n