Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set ViewPager's adapter via Data Binding

Trying to use Android's Data Binding to adapter for a ViewPager (controls slidable Fragments).

FooPagerAdapter.kt:

class FooPagerAdapter(fm: Fragmentmanager, private val mFragments: List<BarFragment>) : FragmentStatePagerAdapter(fm) {
  override fun getItem(position: int): Fragment {
    return mFragments(position)
  }

  override fun getCount(): Int {
    return mFragments.size
  }
}

If done from the Activity, it would look like:

  ..
  mFooViewPager.adapter = FooPagerAdapter(fragmentFamanager, fragmentsList)
  ..

Question:

Now how does one transfer adapter functionality to the binding file to update fragments ViewPager using Data Binding?


Edit:

As I understand it has to be something like this.

activity_foo.xml:

<android.support.v4.view.ViewPager
  ..
  app:fragments"${viewModel.fragments}"/>

And then in a FooViewModel.kt:

fun getFragments(): LiveData<List<BarFragment>>? = mFragments

companion object {
  @BindingAdapter("bind:fragments")
  fun setAdapter(pager: ViewPager, adapter: BarPagerAdapter) {
    pager.adapter = adapter
  }
}

Edit2:

Decided to use a ViewModel directly (without binding) to set ViewPager's adapter.

activity_foo.xml:

<layout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
        <variable
            name="viewModel"
            type="com.foo.bar.viewmodels.FooViewModel"/>
    </data>
    ..
      <android.support.v4.view.ViewPager
          ..
          app:adapter="%{viewModel.adapter}"/>

FooViewModel.kt:

class FooViewModel(application: Application) : AndroidViewModel(application) {
  ..
  fun setAdapter(pager: ViewPager, fragments:List<PeriodFragment>) {
    pager.adapter = PeriodsPagerAdapter(mFragmentManager!!, periods)
  }

Getting:

Error:...layout\activity_foo.xml:39 attribute 'com.foo.bar:adapter' not found

like image 973
0leg Avatar asked Jan 23 '26 14:01

0leg


1 Answers

A @BindingAdapter should be static in Java, thus be annotated with @JvmStatic. Additionally you're supposed to skip all namespaces with the binding attributes in the adapter definition. Also the second parameter needs to reference a type you want to set. In your case this is LiveData<List<BarFragment>>. Then you can create the adapter statically.

companion object {
  @JvmStatic
  @BindingAdapter("fragments")
  fun setAdapter(pager: ViewPager, fragments: LiveData<List<BarFragment>>) {
    pager.adapter = createAdapterForFragments(fragments)
  }
}

But if fragments would be a PagerAdapter, a binding adapter is not necessary at all. As a default implementation the compiler looks for a given setter method for the attribute. So if you use app:adapter, the setAdapter() method will be used automatically. Therefore it should be sufficient to just put this adapter definition in the layout.

<android.support.v4.view.ViewPager
  ...
  app:adapter"@{viewModel.fragments}"/>

I'd suggest to use the latter and setup the adapter with the viewModel not with the data binding.

A little data binding convenience for ViewPager and TabLayout you'll find with ViewPagerDataBinding.

like image 102
tynn Avatar answered Jan 26 '26 06:01

tynn