Monday, July 15, 2013

Fragments and ViewPager with Mvx

I've been toying around with MvvmCross (Mvx) and Fragments lately and found out that my binding for the ViewPager is only working if you are using old type of Activities and Views. So in this blog post I will describe what I did to get the ViewPager to work nicely with Fragments and Mvx.

I have made some code samples which are shown in the bottom of this blog post and which I will refer to. So to start with, let me explain why this approach is necessary. There are currently no official bindings for the ViewPager for Mvx for Xamarin.Android. However, I did make one, and it works pretty well and binds to the ViewPager like you would with a ListView. In fact you can use different ItemTemplates such that you can display different kinds of Views inside the ViewPager. How to do that is decribed in the Working with Collections Tutorial in the MvvmCross Tutorials repository.
With Fragments that approach changes. Now a FragmentPagerAdapter is required, which creates instances of Fragments and keeps track of which are shown on the screen and which to cache, much in the same fashion as a normal Adapter for ListViews. However Fragments are a lot different as they have their own life-cycle and with Mvx each of them have their own ViewModel as well, just like you previously would have a ViewModel for an Activity. The binding of the View associated to a Fragment also happens inside that Fragment. So the binding action which previously was inside the Adapter, now is handled in the Fragment. This means a lot less work for me! So since I cannot use the bindings I previously made I had to come up with something new.

Anyways let us get to the fun stuff and let me explain the code below.
  • Home.axml is the Android View, which contains the ViewPager and an optional ViewPagerIndicator (will post source for this soon, look out for another blog post meanwhile you can use this) - very simple no bindings here.
  • HomeViewModel.cs is a simple ViewModel, similar to one you would use for a Tab kind of View, which instantiates other ViewModels to use for each tab, or in this case for each page in the ViewPager.
  • MvxViewPagerFragmentAdapter.cs is what we need to inform ViewPager about our Fragments. It needs to know about at least the Type of the Fragment and the ViewModel associated to it. The Title is just for convenience when using a ViewPagerIndicator. Basically what happens in GetItem is that a Fragment of a specific Type gets instantiated and the DataContext for that Fragment is set. This way the Fragment itself can create bindings to Properties and Commands internally. GetPageTitleFormatted is simple for a ViewPagerIndicator. FragmentJavaName and FragmentInfo was highly inspired by the MvxTabsFragmentActivity which kind of does the same thing as this Adapter but with a lot more stuff to make it work with a TabHost.
  • HomeView.cs now this last piece of code, simply creates the FragmentInfo instances for the Fragments I want to display in the ViewPager and gives that information to the Adapter which is set for the ViewPager.
This is basically it. See the video for a quick run through of the code and how it looks at the end of it.