4.5 Fragment Slide Shows

A common way to use a fragment is with a ViewPager, which is a container that allows swapping of fragments without changing the entire screen. We’ll be creating a simplified version of the menu view in Eatery:

1. We will first create the classes for our two fragments: LunchFragment and DinnerFragment.

LunchFragment.kt
class LunchFragment: Fragment() {
  companion object {
    fun newInstance(): LunchFragment {
      return LunchFragment()
    }
  }
  override fun onCreateView(inflater: LayoutInflater, 
                            container: ViewGroup?, 
                            savedInstanceState: Bundle?): View? {
    return inflater.inflate(R.layout.fragment_layout, container, false)
  }
}
DinnerFragment.kt
class DinnerFragment: Fragment() {
  companion object {
    fun newInstance(): DinnerFragment {
      return DinnerFragment()
    }
  }
  override fun onCreateView(inflater: LayoutInflater, 
                            container: ViewGroup?, 
                            savedInstanceState: Bundle?): View? {
    return inflater.inflate(R.layout.fragment_layout, container, false)
  }
}

Because a fragment inherits a different parent than an activity, if we want to use activity-specific methods like findViewById(), we'll need access to the root view. We can easily modify the code inside the onCreateView() method.

DinnerFragment.kt
override fun onCreateView(inflater: LayoutInflater, 
                          container: ViewGroup?, 
                          savedInstanceState: Bundle?): View? {
    ...
    val rootView: View = 
        inflater.inflate(R.layout.fragment_layout, container, false)
    
    // use activity-specific methods
    val tv = rootView.findViewById<TextView>(R.id.textview)
    return rootView
}

2. We create a view pager adapter class to manage the changing of fragments. As we can see in the code, each page in the view pager is associated with a fragment.

ViewPagerAdapter.kt
class ViewPagerAdapter(fa: FragmentActivity) : FragmentStateAdapter(fa) {
    override fun getItemCount(): Int = NUM_PAGES
    
    override fun createFragment(position: Int): Fragment {
        return when (position) {
            0 -> LunchFragment()
            1 -> DinnerFragment()
            else -> throw Exception()
        }
    }
}

3. We add the view pager adapter to our activity.

MainActivity.kt
class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    val viewPager = findViewById(R.id.view_pager)

    val pagerAdapter = ViewPagerAdapter(this)
    viewPager.adapter = pagerAdapter
  }
}

The XML to our activity may look something like this, where there is a container for holding the view pager.

main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout   
  ... >
  <androidx.viewpager2.widget.ViewPager2
    android:id="@+id/view_pager"
    ... />
</LinearLayout>

As you can see, setting up a view pager doesn't take too many steps and there is not too much boilerplate code. View pagers are versatile and appear in many mobile designs. We even used a view pager in Eatery! The launch screen of Eatery currently has a view pager with three pages and each of those pages is associated with a fragment.

A unique property of ViewPagers is that it preloads a certain number of pages to the left and right of your currentPage when the adapter is first created in the flow of your app which makes it hard to dynamically respond to changes!

If you are modifying other fragments in your ViewPager or trying to share data in between using techniques from 4.4 Sharing Data Between Fragments or find that none of the views in your fragments are being updated, you MUST call on notifyItemChanged after to refresh the stale data in your fragment from when it was preloaded. NotifyItemChanged takes in the index of the Fragment being refreshed.

ex: viewPager2.adapter.notifyItemChanged(0) refreshes the first fragment in your ViewPager

Last updated