web-dev-qa-db-fra.com

Utiliser la disposition des onglets dans l'architecture MVVM avec la bibliothèque de liaison de données

Je développe une application qui a une disposition d'onglet comme image.

enter image description here

J'aimerais utiliser l'architecture MVVM avec la bibliothèque de liaison de données, mais je suis nouveau avec ce cadre.

Je peux le faire sans utiliser MVVM en configurant normalement la mise en page de l'onglet en utilisant ViewPager comme exemple.

Disposition normale des onglets sans MVVM et liaison de données:

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"  />
</Android.support.design.widget.CoordinatorLayout>

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

Disposition des onglets dans MVVM:

Lors de l'utilisation de MVVM avec la bibliothèque de liaison de données, nous devrons utiliser un modèle de vue pour la vue de présentation des onglets.

Et je ne sais pas comment configurer la disposition des onglets dans le XML et dans le modèle de vue. Comment gérer des événements tels que "appuyer sur un onglet de la mise en page" à l'aide de la bibliothèque de liaison de données

Existe-t-il un exemple d'utilisation de la disposition des onglets dans MVVM avec la bibliothèque de liaison de données?

Merci de votre aide.

14
Jimy25

Activité principale -

    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>

Adaptateur -

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

Je ne sais pas si cela a été récemment introduit, mais avec Android Supporte la version 27.1.1, vous n'avez même pas besoin d'un adaptateur de liaison de données personnalisé, vous pouvez simplement utiliser:

<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}"
            />

Notez que la variable viewPager dans app:setupWithViewPager="@{some_fragment_viewpager}" pointe vers Android:id="@+id/some_fragment_viewpager". Voilà comment se fait la référence au ViewPager (comme par magie je sais)!

ViewModel

public class SomeViewModel {
  public ViewPager.OnPageChangeListener pageChangeListener;
  public SomeFragmentPagerAdapter pagerAdapter;
  // ...
}

FragmentPagerAdapter

public classs SomeFragmentPagerAdapter extends FragmentPagerAdapter {
  public Boolean currentPosition;
}
4
ericn

Voici ma solution pour setUpWithViewpager en utilisant 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);
        }
    }

projet de démonstration complet ici

J'espère que ça aide

3
Phan Van Linh