Programming
How to implement a ViewPager with different Fragments Layouts
Building dynamic and engaging user interfaces in Android often requires displaying a variety of content types within a single, swipeable interface. The ViewPager component is a powerful tool for achieving this, allowing users to navigate between different screens or fragments with intuitive gestures. However, many developers encounter a common challenge: how to implement a ViewPager with different Fragments / Layouts seamlessly. This guide will walk you through the process of creating a flexible ViewPager that can display diverse content, from simple text views to complex forms, ensuring a smooth and responsive user experience. Mastering this technique is crucial for developing modern Android applications that offer rich, interactive navigation and present information effectively.
Understanding ViewPager and Its Adapters
The ViewPager is an essential component within Android’s UI toolkit, designed to display a series of pages or screens that users can swipe between. At its heart, the ViewPager relies on an adapter to provide the views that it displays. For displaying fragments, you’ll primarily work with two types of adapters: FragmentPagerAdapter and FragmentStatePagerAdapter. Understanding the distinction between these is key to efficient implementation, especially when dealing with varied content.
FragmentPagerAdapter is generally used when you have a small, fixed number of well-defined fragments. It keeps fragments in memory once they are instantiated, only detaching their views when they are no longer visible. While this offers quick access to fragments when swiping back and forth, it can lead to higher memory consumption if you have many fragments, particularly those with complex layouts or large datasets. For scenarios where the number of pages is relatively constant and not excessively large, this adapter provides a straightforward and performant solution.
Conversely, FragmentStatePagerAdapter is ideal for handling a large number of dynamic fragments, or when fragments might need to be frequently added or removed. This adapter only keeps the saved state of the fragments, destroying the fragment instances themselves when they are not in focus. This significantly reduces memory usage compared to FragmentPagerAdapter, making it suitable for applications like image galleries or onboarding flows with many steps. According to the Android Developers documentation, choosing the correct adapter depends heavily on the specific use case and the lifecycle management requirements of your fragments.
Designing Diverse Fragments for Your ViewPager
To implement a ViewPager with different Fragments / Layouts, the first step involves creating distinct fragment classes and their corresponding XML layout files for each type of content you wish to display. Each fragment should encapsulate a specific piece of UI and its associated logic, promoting modularity and reusability within your application. For instance, one fragment might display an image carousel, while another presents a detailed article, and a third offers a form for user input.
When designing these fragments, consider their unique requirements. A “Welcome” fragment might have a large image and a button, whereas a “Settings” fragment could feature multiple toggle switches and text fields. Each fragment’s layout (e.g., fragment_welcome.xml, fragment_settings.xml) will define its visual structure. The corresponding Kotlin or Java class (e.g., WelcomeFragment.kt, SettingsFragment.kt) will handle inflating this layout, binding data, and managing user interactions. This separation of concerns is fundamental to good Android development practices and makes it easier to manage complex UIs.
It’s also beneficial to consider how data will be passed to these fragments. For example, if your fragments display dynamic content, you might pass arguments to them during instantiation using a Bundle. This allows a single fragment class to display variations of a layout or data based on the information it receives. By carefully planning and designing each individual fragment, you lay a solid foundation for a robust and adaptable ViewPager implementation that can handle diverse content types efficiently.
The core of displaying different fragments in a ViewPager lies in creating a custom adapter that intelligently provides the correct fragment for each position. This custom adapter will extend either FragmentPagerAdapter or FragmentStatePagerAdapter, depending on your memory and lifecycle needs. Below, we outline the steps to create such an adapter:
- Define Fragment List/Data Source: First, you need a way to tell your adapter which fragments to display and in what order. This could be a simple list of fragment classes, a list of data objects that each correspond to a fragment type, or an enum. For example, a
List<Class<? extends Fragment>>or aList<String>where each string represents a page type. - Override Constructor: Your custom adapter’s constructor will typically take a
FragmentManagerinstance and your list of fragments/data. ThisFragmentManageris crucial for managing the fragment transactions. - Implement
getItem(int position): This is the most critical method. Based on theposition, you will instantiate and return the appropriate fragment. Here, you’ll use conditional logic (e.g.,if/else ifstatements or awhenexpression in Kotlin) to determine which fragment class to create and return. This is where the magic happens for implementing a ViewPager with different Fragments / Layouts. - Implement
getCount(): This method simply returns the total number of pages/fragments your ViewPager should display. It should correspond to the size of your fragment list or data source. - (Optional) Implement
getPageTitle(int position): If you’re using aTabLayoutin conjunction with your ViewPager, this method provides the title for each tab. Again, use conditional logic based on thepositionto return the relevant title for each distinct fragment.
For example, if you have Question & Answer :
When I start an activity which implements viewpager, the viewpager created various fragments. I want to use different layouts for each fragment, but the problem is that viewpager shows only two layouts at the max (second layout on all of the remaining fragments after 1).
Here is the code for SwipeActivity which implements the viewpager :
public class SwipeActivity extends FragmentActivity { MyPageAdapter pageAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_swipe); pageAdapter = new MyPageAdapter(getSupportFragmentManager()); ViewPager pager=(ViewPager)findViewById(R.id.pager); pager.setAdapter(pageAdapter); ActionBar bar = getActionBar(); bar.setDisplayHomeAsUpEnabled(true); } /** * Custom Page adapter */ private class MyPageAdapter extends FragmentPagerAdapter { public MyPageAdapter(FragmentManager fm) { super(fm); } @Override public int getCount() { return 5; } @Override public Fragment getItem(int position) { switch(position) { case 0: return new MyFragment(); case 1: return SecondFragment.newInstance("asdasd"); default : return RamFragment.newInstance("s"); } } } }
Here is the code for the fragments
public class MyFragment extends Fragment { @Override public View onCreateView(LayoutInflater paramLayoutInflater, ViewGroup paramViewGroup, Bundle paramBundle) { return paramLayoutInflater.inflate(R.layout.processorlayout, paramViewGroup, false); } }
I used 5 fragments like this, all having different layouts, but the viewpager shows only 2 at the max.
EDIT : code for SecondFragment
public class SecondFragment extends Fragment { public static final String EXTRA_MESSAGE = "EXTRA_MESSAGE"; public static final SecondFragment newInstance(String paramString) { SecondFragment f = new SecondFragment(); Bundle localBundle = new Bundle(1); localBundle.putString("EXTRA_MESSAGE", paramString); f.setArguments(localBundle); return f; } @Override public View onCreateView(LayoutInflater paramLayoutInflater, ViewGroup paramViewGroup, Bundle paramBundle) { return paramLayoutInflater.inflate(R.layout.motherboardlayout, paramViewGroup, false); } }
As this is a very frequently asked question, I wanted to take the time and effort to explain the ViewPager with multiple Fragments and Layouts in detail. Here you go.
ViewPager with multiple Fragments and Layout files - How To
The following is a complete example of how to implement a ViewPager with different fragment Types and different layout files.
In this case, I have 3 Fragment classes, and a different layout file for each class. In order to keep things simple, the fragment-layouts only differ in their background color. Of course, any layout-file can be used for the Fragments.
FirstFragment.java has a orange background layout, SecondFragment.java has a green background layout and ThirdFragment.java has a red background layout. Furthermore, each Fragment displays a different text, depending on which class it is from and which instance it is.
Also be aware that I am using the support-library’s Fragment: android.support.v4.app.Fragment
MainActivity.java (Initializes the Viewpager and has the adapter for it as an inner class). Again have a look at the imports. I am using the android.support.v4 package.
import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.view.ViewPager; public class MainActivity extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ViewPager pager = (ViewPager) findViewById(R.id.viewPager); pager.setAdapter(new MyPagerAdapter(getSupportFragmentManager())); } private class MyPagerAdapter extends FragmentPagerAdapter { public MyPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int pos) { switch(pos) { case 0: return FirstFragment.newInstance("FirstFragment, Instance 1"); case 1: return SecondFragment.newInstance("SecondFragment, Instance 1"); case 2: return ThirdFragment.newInstance("ThirdFragment, Instance 1"); case 3: return ThirdFragment.newInstance("ThirdFragment, Instance 2"); case 4: return ThirdFragment.newInstance("ThirdFragment, Instance 3"); default: return ThirdFragment.newInstance("ThirdFragment, Default"); } } @Override public int getCount() { return 5; } } }
activity_main.xml (The MainActivitys .xml file) - a simple layout file, only containing the ViewPager that fills the whole screen.
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/viewPager" android:layout_width="fill_parent" android:layout_height="fill_parent" />
The Fragment classes, FirstFragment.java import android.support.v4.app.Fragment;
public class FirstFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.first_frag, container, false); TextView tv = (TextView) v.findViewById(R.id.tvFragFirst); tv.setText(getArguments().getString("msg")); return v; } public static FirstFragment newInstance(String text) { FirstFragment f = new FirstFragment(); Bundle b = new Bundle(); b.putString("msg", text); f.setArguments(b); return f; } }
first_frag.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/holo_orange_dark" > <TextView android:id="@+id/tvFragFirst" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:textSize="26dp" android:text="TextView" /> </RelativeLayout>
SecondFragment.java
public class SecondFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.second_frag, container, false); TextView tv = (TextView) v.findViewById(R.id.tvFragSecond); tv.setText(getArguments().getString("msg")); return v; } public static SecondFragment newInstance(String text) { SecondFragment f = new SecondFragment(); Bundle b = new Bundle(); b.putString("msg", text); f.setArguments(b); return f; } }
second_frag.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/holo_green_dark" > <TextView android:id="@+id/tvFragSecond" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:textSize="26dp" android:text="TextView" /> </RelativeLayout>
ThirdFragment.java
public class ThirdFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.third_frag, container, false); TextView tv = (TextView) v.findViewById(R.id.tvFragThird); tv.setText(getArguments().getString("msg")); return v; } public static ThirdFragment newInstance(String text) { ThirdFragment f = new ThirdFragment(); Bundle b = new Bundle(); b.putString("msg", text); f.setArguments(b); return f; } }
third_frag.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/holo_red_light" > <TextView android:id="@+id/tvFragThird" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:textSize="26dp" android:text="TextView" /> </RelativeLayout>
The end result is the following:
The Viewpager holds 5 Fragments, Fragments 1 is of type FirstFragment, and displays the first_frag.xml layout, Fragment 2 is of type SecondFragment and displays the second_frag.xml, and Fragment 3-5 are of type ThirdFragment and all display the third_frag.xml.

Above you can see the 5 Fragments between which can be switched via swipe to the left or right. Only one Fragment can be displayed at the same time of course.
Last but not least:
I would recommend that you use an empty constructor in each of your Fragment classes.
Instead of handing over potential parameters via constructor, use the newInstance(...) method and the Bundle for handing over parameters.
This way if detached and re-attached the object state can be stored through the arguments. Much like Bundles attached to Intents.