ViewPager
- https://developer.android.com/reference/android/support/v4/view/ViewPager.html
- only available in the support library.
- Requires a PagerAdapter
- Use FragmentStatePagerAdapter, a subclass of PagerAdapter to take care of the details
- By default, ViewPager loads the item currently on screen plus one neighboring page in each direction so that the response to a swipe is immediate.
- By default, hte ViewPager shows the first item in its PagerAdapter
- Create a layout file for that activity, using
android.support.v4.view.ViewPager
- Create an activity that is an subclass of FragmentActivity
- Inflate the view
- Prepare the data set
- Set up the pager adapter
- Get a fragmentManager
- Implement FragmentStatePagerAdapter's getItem(...) and getCount()
- Set the initial pager item
- Don't forget to add the newly-created activity to the manifest
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/crimePager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
/**
* Inherit FragmentActivity because we use support fragments.
* A ViewPager is only available in the support library and requires a PagerAdapter, such as
* FragmentStatePagerAdapter and FragmentPagerAdapter.
* https://developer.android.com/reference/android/support/v4/view/ViewPager.html
*/
class CrimePagerActivity : FragmentActivity() {
private val TAG = javaClass.simpleName
companion object {
private val EXTRA_CRIME_ID = "${CrimePagerActivity::class.java.canonicalName}.EXTRA_CRIME_ID"
// Define an extra intent for starting this activity.
fun newIntent(packageContext: Context, crimeId: UUID): Intent {
return Intent(packageContext, CrimePagerActivity::class.java).apply {
putExtra(EXTRA_CRIME_ID, crimeId)
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
Log.d(TAG, "onCreate")
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_crime_pager)
// Get a crime id from the intent so that we can determine the initial item.
val crimeId = intent.getSerializableExtra(EXTRA_CRIME_ID) as UUID
val crimes = CrimeLab.get(this).crimes
crimePager.adapter = object : FragmentStatePagerAdapter(supportFragmentManager) {
override fun getItem(position: Int): Fragment = CrimeFragment.newInstance(crimes[position].id)
override fun getCount(): Int = crimes.size
}
// Set initial pager item based on the id provided by the previous activity.
crimePager.currentItem = crimes.indexOfFirst { it.id == crimeId }
}
}
FragmentStatePagerAdapter vs FragmentPagerAdapter
- Only different when a fragment is no longer needed
FragmentStatePagerAdapter
- Calls
remove(fragment)
on the transaction
- Destroys the unneeded fragment
- The state will be saved using the fragment's Bundle from onSavedInstanceState(Bundle)
- When the user navigated back, the new fragment will be restored using that instance state.
- More frugal with memory
- E.g., a list of items
FragmentPagerAdapter
- Calls
detach(fragment)
on the transaction
- Unneeded fragment is destroyed
- Destroys the unneeded fragment's view, but leaves the fragment instance alive in the FragmentManager.
- The fragments created by FragmentPagerAdapter are never destroyed.
- Suitable with a small interface a fixed number of fragments.
- E.g., a tabbed interface
Customizing the PagerAdaper interface
- When we want to host something other than Fragments, such as normal View objects in a ViewPager, we need to implement the raw PagerAdapter interface.
- PagerAdapter is more complicated then Adapter because it does more of the work of managing views than Adapter does.
- Instead of onBindViewHolder(...), PagerAdapter has:
- instantiateItem(ViewGroup container, int pos)
- destroyItem(ViewGroup container, int pos, Object o)
- isViewFromObject(View v, Object o)