Use Tab layout in MVVM architecture with the data binding library
MainActivity -
public class MainActivity extends Activity
{
@Override
protected void onCreate(@Nullable final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
App.get(this).component().inject(this);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.setHandler(this);
binding.setManager(getSupportFragmentManager());
}
@BindingAdapter({"bind:handler"})
public static void bindViewPagerAdapter(final ViewPager view, final MainActivity activity)
{
final MainActionsAdapter adapter = new MainActionsAdapter(view.getContext(), activity.getSupportFragmentManager());
view.setAdapter(adapter);
}
@BindingAdapter({"bind:pager"})
public static void bindViewPagerTabs(final TabLayout view, final ViewPager pagerView)
{
view.setupWithViewPager(pagerView, true);
}
}
xml -
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:fresco="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="android.view.View" />
<variable
name="handler"
type="com.ui.main.MainActivity" />
<variable
name="manager"
type="android.support.v4.app.FragmentManager" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
app:title="@string/app_name"
app:titleMarginStart="8dp" />
<android.support.design.widget.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:pager="@{(pager)}">
</android.support.design.widget.TabLayout>
<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:handler="@{handler}" />
</LinearLayout>
</layout>
Adapter -
public class MainSectionsAdapter extends FragmentPagerAdapter
{
private static final int CONTACTS = 0;
private static final int CALLS = 1;
private static final int CHATS = 2;
private static final int[] TABS = new int[]{CONTACTS, CALLS, CHATS};
private Context mContext;
public MainSectionsAdapter(final Context context, final FragmentManager fm)
{
super(fm);
mContext = context.getApplicationContext();
}
@Override
public Fragment getItem(int position)
{
switch (TABS[position])
{
case CONTACTS:
return ContactsFragment.newInstance();
case CALLS:
return CallsFragment.newInstance();
case CHATS:
return ChatsFragment.newInstance();
}
return null;
}
@Override
public int getCount()
{
return TABS.length;
}
@Override
public CharSequence getPageTitle(int position)
{
switch (TABS[position])
{
case CONTACTS:
return mContext.getResources().getString(R.string.contacts);
case CALLS:
return mContext.getResources().getString(R.string.calls);
case CHATS:
return mContext.getResources().getString(R.string.chats);
}
return null;
}
}
I'm not sure if this is newly introduced recently but with Android Support version 27.1.1, you don't even even need a custom data binding adapter, you can simply use:
<android.support.design.widget.TabLayout
android:id="@+id/tl_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:setupWithViewPager="@{some_fragment_viewpager}"
app:tabSelectedTextColor="@android:color/white"
app:tabTextColor="@color/v5_grey_55"
/>
<android.support.v4.view.ViewPager
android:id="@+id/some_fragment_viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:addOnPageChangeListener="@{vm.pageChangeListener}"
app:setAdapter="@{vm.pageAdapter}"
app:setCurrentItem="@{vm.pageChangeListener.currentPosition}"
/>
Take note that the viewPager
variable in app:setupWithViewPager="@{some_fragment_viewpager}"
points to android:id="@+id/some_fragment_viewpager"
.
That's how the reference to the ViewPager is done (like magic I know)!
ViewModel
public class SomeViewModel {
public ViewPager.OnPageChangeListener pageChangeListener;
public SomeFragmentPagerAdapter pagerAdapter;
// ...
}
FragmentPagerAdapter
public classs SomeFragmentPagerAdapter extends FragmentPagerAdapter {
public Boolean currentPosition;
}