Use Tab layout in MVVM architecture with the data binding library

你离开我真会死。 提交于 2019-12-31 09:45:24

问题


I am developing an app that has tab layout as the image.

I’d like to use MVVM architecture with data binding library but I am new with this framework.

I can do this without using MVVM by normally setup tab layout using ViewPager as this sample.

Normal tab layout without MVVM and data binding:

activity_main.xml:

<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">

<android.support.design.widget.AppBarLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        app:layout_scrollFlags="scroll|enterAlways"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

    <android.support.design.widget.TabLayout
        android:id="@+id/tabs"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:tabMode="fixed"
        app:tabGravity="fill"/>
</android.support.design.widget.AppBarLayout>

<android.support.v4.view.ViewPager
    android:id="@+id/viewpager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"  />

MainActivity.java:

public class MainActivity extends AppCompatActivity {

private Toolbar toolbar;
private TabLayout tabLayout;
private ViewPager viewPager;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    getSupportActionBar().setDisplayHomeAsUpEnabled(true);

    viewPager = (ViewPager) findViewById(R.id.viewpager);
    setupViewPager(viewPager);

    tabLayout = (TabLayout) findViewById(R.id.tabs);
    tabLayout.setupWithViewPager(viewPager);
}

private void setupViewPager(ViewPager viewPager) {
    ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
    adapter.addFragment(new OneFragment(), "ONE");
    adapter.addFragment(new TwoFragment(), "TWO");
    adapter.addFragment(new ThreeFragment(), "THREE");
    viewPager.setAdapter(adapter);
}

class ViewPagerAdapter extends FragmentPagerAdapter {
    private final List<Fragment> mFragmentList = new ArrayList<>();
    private final List<String> mFragmentTitleList = new ArrayList<>();

    public ViewPagerAdapter(FragmentManager manager) {
        super(manager);
    }

    @Override
    public Fragment getItem(int position) {
        return mFragmentList.get(position);
    }

    @Override
    public int getCount() {
        return mFragmentList.size();
    }

    public void addFragment(Fragment fragment, String title) {
        mFragmentList.add(fragment);
        mFragmentTitleList.add(title);
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return mFragmentTitleList.get(position);
    }
}

}

Tab layout in MVVM:

When using MVVM with data binding library, we will have to use a view model for the tab layout view.

And I don’t know how to setup tab layout in the XML and also in the view model. How to handle events such as “tap on one tab of the layout” using data binding library

Is there any sample of using Tab layout in MVVM with data binding library ?

Thanks for your help.


回答1:


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;
    }
}



回答2:


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;
}



回答3:


Here is my solution for setUpWithViewpager using databinding:

public class BindingUtil
{
    @BindingAdapter({ "setUpWithViewpager" })
    public static void setUpWithViewpager(final TabLayout tabLayout, ViewPager viewPager)
    {
        viewPager.addOnAdapterChangeListener(new ViewPager.OnAdapterChangeListener()
        {
            @Override
            public void onAdapterChanged(@NonNull ViewPager viewPager, @Nullable PagerAdapter oldAdapter, @Nullable PagerAdapter newAdapter)
            {
                if (oldAdapter == null && (newAdapter == null || newAdapter.getCount() == 0))
                {
                    // this function will helpful when 
                    // we don't create viewpager immediately 
                    // when view created (this mean we create
                    // will pager after a period time)
                    return;
                }
                tabLayout.setupWithViewPager(viewPager);
            }
        });
    }
}

xml

<android.support.design.widget.TabLayout
     ... 
     app:setUpWithViewpager="@{ viewPager }"
/>

<android.support.v4.view.ViewPager
     ...
     android:id="@+id/viewPager"
     app:adapter="@{viewModel.pagerAdapter}"
/>

ViewModel

public class MainViewModel extends BaseObservable
{

    @Bindable
    public PagerAdapter getPagerAdapter()
    {
        return adapter;
    }

    private void createViewPagerAdapter()
    {
        ...
        notifyPropertyChanged(BR.pagerAdapter);
    }
}

full demo project here

Hope it help



来源:https://stackoverflow.com/questions/41718377/use-tab-layout-in-mvvm-architecture-with-the-data-binding-library

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!