Использование макета вкладки в архитектуре MVVM с библиотекой привязки данных
Я разрабатываю приложение с макетом вкладки в качестве изображения.
Id нравится использовать архитектуру MVVM с библиотекой привязки данных, но я новичок в этой структуре.
Я могу сделать это, не используя MVVM, с помощью обычной настройки вкладки, используя ViewPager в качестве этого примера.
Обычная компоновка вкладок без MVVM и привязка данных:
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);
}
}
}
Размещение вкладок в MVVM:
При использовании MVVM с библиотекой привязки данных мы должны будем использовать модель представления для представления макета вкладки.
И я не знаю, как настроить компоновку вкладок в XML, а также в модели представления. Как обрабатывать такие события, как "нажимать на одну вкладку макета", используя библиотеку привязки данных
Есть ли образец использования макета вкладки в MVVM с библиотекой привязки данных?
Спасибо за вашу помощь.
Ответы
Ответ 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>
Адаптер -
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
Я не уверен, что это недавно появилось недавно, но с версией поддержки Android 27.1.1 вам даже не нужен специальный адаптер привязки данных, вы можете просто использовать:
<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}"
/>
Обратите внимание, что переменная viewPager
в app:setupWithViewPager="@{some_fragment_viewpager}"
указывает на android:id="@+id/some_fragment_viewpager"
.
Вот как делается ссылка на ViewPager (как по волшебству я знаю)!
ViewModel
public class SomeViewModel {
public ViewPager.OnPageChangeListener pageChangeListener;
public SomeFragmentPagerAdapter pagerAdapter;
// ...
}
FragmentPagerAdapter
public classs SomeFragmentPagerAdapter extends FragmentPagerAdapter {
public Boolean currentPosition;
}
Ответ 3
Вот мое решение для setUpWithViewpager
с помощью 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);
}
}
полный демо-проект здесь
Надеюсь, что это поможет