Бесконечный ViewPager с TabLayout
Я реализовал бесконечный ViewPager на месте https://github.com/JoachimR/AnyDayViewPager. Однако вместо использования PagerTabStrip я бы предпочел использовать CoordinatorLayout с TabLayout. Но при настройке TabLayout с помощью viewpager (я предполагаю, что существует "бесконечное количество фрагментов ViewPager"), приложение застревает.
Как я могу решить эту проблему?
Вот код (другие файлы, которые я не изменил, можно найти в https://github.com/JoachimR/AnyDayViewPager, например, FragmentContent.java, CachingFragmentStatePagerAdapter.java, TimeUtils.java и т. Д.)
MainActivity.java
import android.content.Context;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.view.ViewPager;
import android.support.design.widget.TabLayout;
import android.os.Bundle;
import java.util.Calendar;
public class MainActivity extends FragmentActivity {
private static Context mContext;
private CachingFragmentStatePagerAdapter adapterViewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this;
ViewPager vpPager = (ViewPager) findViewById(R.id.vpPager);
adapterViewPager = new MyPagerAdapter(getSupportFragmentManager());
vpPager.setAdapter(adapterViewPager);
// set pager to current date
vpPager.setCurrentItem(TimeUtils.getPositionForDay(Calendar.getInstance()));
/** THIS IS WHERE THE ISSUES ARISE **/
TabLayout tabLayoutDiary = (TabLayout) findViewById(R.id.diary_tabs);
tabLayoutDiary.setupWithViewPager(vpPager);
}
public static class MyPagerAdapter extends CachingFragmentStatePagerAdapter {
private Calendar cal;
public MyPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
@Override
public int getCount() {
return TimeUtils.DAYS_OF_TIME;
}
@Override
public Fragment getItem(int position) {
long timeForPosition = TimeUtils.getDayForPosition(position).getTimeInMillis();
return FragmentContent.newInstance(timeForPosition);
}
@Override
public CharSequence getPageTitle(int position) {
Calendar cal = TimeUtils.getDayForPosition(position);
return TimeUtils.getFormattedDate(mContext, cal.getTimeInMillis());
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<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"
xmlns:fab="http://schemas.android.com/tools">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.TabLayout
android:id="@+id/diary_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="scrollable"/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="@+id/vpPager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</android.support.design.widget.CoordinatorLayout>
2 ответа
Возможно, из-за этой ошибки: https://code.google.com/p/android/issues/detail?id=180027
TabLayout создает вкладку TextView для каждой страницы вашего ViewPager, а не динамически создает и перерабатывает TextViews. Как вы видите, это просто взорвется, если вы попытаетесь подделать бесконечный ViewPager.
К сожалению, пока нет исправления. Вы можете попробовать использовать https://github.com/nshmura/RecyclerTabLayout который был связан с ошибкой, но я сам не использовал его.
Например, если у вас есть день недели в виде вкладки
enum class WeekDay(val abbreviation: String, val position: Int) {
FALSE_SATURDAY("", 0),
MONDAY("Mon", 1),
TUESDAY("Tue", 2),
WEDNESDAY("Wed", 3),
THURSDAY("Thu", 4),
FRIDAY("Fri", 5),
SATURDAY("Sat", 6),
FALSE_MONDAY("", 7)
}
При настройке адаптера ViewPager привязывайте tabLayout к ViewPager. Текущий список страниц в адаптере ViewPager должен содержать еще две страницы в нулевой и последней позициях.
Если список страниц всегда разный:
- В нулевой позиции содержится последняя страница предыдущего списка страниц адаптера ViewPager.
- В последней позиции содержит первую страницу следующего списка страниц в адаптере ViewPager.
Если список страниц всегда один и тот же:
- В нулевой позиции содержится последняя страница в списке.
- Последняя позиция содержит первую страницу в списке.
TabLayoutMediator(
binding.tabLayout, binding.viewPager2
) { tab: TabLayout.Tab, position: Int ->
if (position == WeekDay.FALSE_MONDAY.position || position == WeekDay.FALSE_SATURDAY.position) {
tab.view.visibility = View.GONE
}
tab.text = listOf(
WeekDay.FALSE_SATURDAY.abbreviation,
WeekDay.MONDAY.abbreviation,
WeekDay.TUESDAY.abbreviation,
WeekDay.WEDNESDAY.abbreviation,
WeekDay.THURSDAY.abbreviation,
WeekDay.FRIDAY.abbreviation,
WeekDay.SATURDAY.abbreviation,
WeekDay.FALSE_MONDAY.abbreviation
)[position]
}.attach()
Затем вам нужно зарегистрировать обратный вызов в ViewPager2.
binding.viewPager2.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
private var state = -1
override fun onPageScrollStateChanged(state: Int) {
super.onPageScrollStateChanged(state)
if (binding.viewPager2.currentItem == WeekDay.FALSE_SATURDAY.position && this.state == SCROLL_STATE_SETTLING) {
binding.viewPager2.setCurrentItem(WeekDay.SATURDAY.position, false)
}
if (binding.viewPager2.currentItem == WeekDay.FALSE_MONDAY.position && this.state == SCROLL_STATE_SETTLING) {
binding.viewPager2.setCurrentItem(WeekDay.MONDAY.position, false)
}
this.state = state
}})
this.state == SCROLL_STATE_SETTLING
означает, что пользователь поднял палец после перетаскивания