Merge pull request #4020 from ebraminio/rtl
Adopt the project with ViewPager2
This commit is contained in:
commit
b870c233ee
|
@ -142,6 +142,7 @@ dependencies {
|
|||
implementation "androidx.preference:preference:1.1.0"
|
||||
implementation "androidx.gridlayout:gridlayout:1.0.0"
|
||||
implementation "androidx.recyclerview:recyclerview:1.1.0"
|
||||
implementation "androidx.viewpager2:viewpager2:1.0.0"
|
||||
implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0"
|
||||
implementation "androidx.media:media:1.1.0"
|
||||
implementation "androidx.work:work-runtime:$workManagerVersion"
|
||||
|
|
|
@ -4,8 +4,10 @@ import android.content.Context;
|
|||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
|
@ -31,9 +33,10 @@ public class ViewPagerBottomSheetBehavior<V extends View> extends BottomSheetBeh
|
|||
return view;
|
||||
}
|
||||
|
||||
if (view instanceof ViewPager) {
|
||||
ViewPager viewPager = (ViewPager) view;
|
||||
View currentViewPagerChild = viewPager.getChildAt(viewPager.getCurrentItem());
|
||||
if (view instanceof ViewPager2) {
|
||||
ViewPager2 viewPager = (ViewPager2) view;
|
||||
RecyclerView recycler = (RecyclerView) viewPager.getChildAt(0);
|
||||
View currentViewPagerChild = recycler.getChildAt(viewPager.getCurrentItem());
|
||||
if (currentViewPagerChild != null) {
|
||||
return findScrollingChild(currentViewPagerChild);
|
||||
}
|
||||
|
|
|
@ -13,20 +13,28 @@ import android.widget.ImageButton;
|
|||
import android.widget.ProgressBar;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentPagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.CastEnabledActivity;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.core.event.FavoritesEvent;
|
||||
import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
|
||||
import de.danoeh.antennapod.core.feed.Chapter;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.feed.util.PlaybackSpeedUtils;
|
||||
|
@ -50,12 +58,6 @@ import io.reactivex.Maybe;
|
|||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Shows the audio player.
|
||||
|
@ -73,7 +75,7 @@ public class AudioPlayerFragment extends Fragment implements
|
|||
|
||||
PlaybackSpeedIndicatorView butPlaybackSpeed;
|
||||
TextView txtvPlaybackSpeed;
|
||||
private ViewPager pager;
|
||||
private ViewPager2 pager;
|
||||
private PagerIndicatorView pageIndicator;
|
||||
private TextView txtvPosition;
|
||||
private TextView txtvLength;
|
||||
|
@ -127,11 +129,10 @@ public class AudioPlayerFragment extends Fragment implements
|
|||
sbPosition.setOnSeekBarChangeListener(this);
|
||||
|
||||
pager = root.findViewById(R.id.pager);
|
||||
AudioPlayerPagerAdapter pagerAdapter = new AudioPlayerPagerAdapter(getChildFragmentManager());
|
||||
pager.setAdapter(pagerAdapter);
|
||||
pager.setAdapter(new AudioPlayerPagerAdapter(this));
|
||||
// Required for getChildAt(int) in ViewPagerBottomSheetBehavior to return the correct page
|
||||
pager.setOffscreenPageLimit(NUM_CONTENT_FRAGMENTS);
|
||||
pager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
|
||||
pager.setOffscreenPageLimit((int) NUM_CONTENT_FRAGMENTS);
|
||||
pager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
pager.post(() -> ((MainActivity) getActivity()).getBottomSheet().updateScrollingChild());
|
||||
|
@ -502,30 +503,30 @@ public class AudioPlayerFragment extends Fragment implements
|
|||
return false;
|
||||
}
|
||||
|
||||
private static class AudioPlayerPagerAdapter extends FragmentPagerAdapter {
|
||||
private static class AudioPlayerPagerAdapter extends FragmentStateAdapter {
|
||||
private static final String TAG = "AudioPlayerPagerAdapter";
|
||||
|
||||
public AudioPlayerPagerAdapter(FragmentManager fm) {
|
||||
super(fm);
|
||||
public AudioPlayerPagerAdapter(@NonNull Fragment fragment) {
|
||||
super(fragment);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
public Fragment createFragment(int position) {
|
||||
Log.d(TAG, "getItem(" + position + ")");
|
||||
switch (position) {
|
||||
case POS_COVER:
|
||||
return new CoverFragment();
|
||||
case POS_DESCR:
|
||||
return new ItemDescriptionFragment();
|
||||
default:
|
||||
case POS_CHAPTERS:
|
||||
return new ChaptersFragment();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
public int getItemCount() {
|
||||
return NUM_CONTENT_FRAGMENTS;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,10 +86,15 @@ public class CompletedDownloadsFragment extends Fragment {
|
|||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
setHasOptionsMenu(true);
|
||||
loadItems();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
setHasOptionsMenu(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
|
|
|
@ -50,6 +50,12 @@ public class DownloadLogFragment extends ListFragment {
|
|||
loadItems();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
setHasOptionsMenu(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
|
@ -61,8 +67,6 @@ public class DownloadLogFragment extends ListFragment {
|
|||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
setHasOptionsMenu(true);
|
||||
|
||||
// add padding
|
||||
final ListView lv = getListView();
|
||||
lv.setClipToPadding(false);
|
||||
|
|
|
@ -2,19 +2,21 @@ package de.danoeh.antennapod.fragment;
|
|||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Bundle;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentPagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.google.android.material.tabs.TabLayoutMediator;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
|
||||
/**
|
||||
|
@ -29,10 +31,11 @@ public class DownloadsFragment extends Fragment {
|
|||
public static final int POS_RUNNING = 0;
|
||||
private static final int POS_COMPLETED = 1;
|
||||
public static final int POS_LOG = 2;
|
||||
private static final int TOTAL_COUNT = 3;
|
||||
|
||||
private static final String PREF_LAST_TAB_POSITION = "tab_position";
|
||||
|
||||
private ViewPager viewPager;
|
||||
private ViewPager2 viewPager;
|
||||
private TabLayout tabLayout;
|
||||
|
||||
@Override
|
||||
|
@ -44,12 +47,30 @@ public class DownloadsFragment extends Fragment {
|
|||
((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
|
||||
|
||||
viewPager = root.findViewById(R.id.viewpager);
|
||||
DownloadsPagerAdapter pagerAdapter = new DownloadsPagerAdapter(getChildFragmentManager(), getResources());
|
||||
viewPager.setAdapter(pagerAdapter);
|
||||
viewPager.setAdapter(new DownloadsPagerAdapter(this));
|
||||
|
||||
// Give the TabLayout the ViewPager
|
||||
tabLayout = root.findViewById(R.id.sliding_tabs);
|
||||
tabLayout.setupWithViewPager(viewPager);
|
||||
new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> {
|
||||
switch (position) {
|
||||
case POS_RUNNING:
|
||||
tab.setText(R.string.downloads_running_label);
|
||||
break;
|
||||
case POS_COMPLETED:
|
||||
tab.setText(R.string.downloads_completed_label);
|
||||
break;
|
||||
case POS_LOG:
|
||||
tab.setText(R.string.downloads_log_label);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}).attach();
|
||||
|
||||
// restore our last position
|
||||
SharedPreferences prefs = getActivity().getSharedPreferences(TAG, Context.MODE_PRIVATE);
|
||||
int lastPosition = prefs.getInt(PREF_LAST_TAB_POSITION, 0);
|
||||
viewPager.setCurrentItem(lastPosition, false);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
@ -73,56 +94,29 @@ public class DownloadsFragment extends Fragment {
|
|||
editor.apply();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
public static class DownloadsPagerAdapter extends FragmentStateAdapter {
|
||||
|
||||
// restore our last position
|
||||
SharedPreferences prefs = getActivity().getSharedPreferences(TAG, Context.MODE_PRIVATE);
|
||||
int lastPosition = prefs.getInt(PREF_LAST_TAB_POSITION, 0);
|
||||
viewPager.setCurrentItem(lastPosition);
|
||||
}
|
||||
|
||||
public static class DownloadsPagerAdapter extends FragmentPagerAdapter {
|
||||
|
||||
final Resources resources;
|
||||
|
||||
public DownloadsPagerAdapter(FragmentManager fm, Resources resources) {
|
||||
super(fm);
|
||||
this.resources = resources;
|
||||
DownloadsPagerAdapter(@NonNull Fragment fragment) {
|
||||
super(fragment);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
public Fragment createFragment(int position) {
|
||||
switch (position) {
|
||||
case POS_RUNNING:
|
||||
return new RunningDownloadsFragment();
|
||||
case POS_COMPLETED:
|
||||
return new CompletedDownloadsFragment();
|
||||
default:
|
||||
case POS_LOG:
|
||||
return new DownloadLogFragment();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getPageTitle(int position) {
|
||||
switch (position) {
|
||||
case POS_RUNNING:
|
||||
return resources.getString(R.string.downloads_running_label);
|
||||
case POS_COMPLETED:
|
||||
return resources.getString(R.string.downloads_completed_label);
|
||||
case POS_LOG:
|
||||
return resources.getString(R.string.downloads_log_label);
|
||||
default:
|
||||
return super.getPageTitle(position);
|
||||
}
|
||||
public int getItemCount() {
|
||||
return TOTAL_COUNT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,13 +6,17 @@ import android.os.Bundle;
|
|||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentPagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.google.android.material.tabs.TabLayoutMediator;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
|
||||
public class EpisodesFragment extends Fragment {
|
||||
|
@ -27,7 +31,7 @@ public class EpisodesFragment extends Fragment {
|
|||
|
||||
|
||||
private TabLayout tabLayout;
|
||||
private ViewPager viewPager;
|
||||
private ViewPager2 viewPager;
|
||||
|
||||
//Mandatory Constructor
|
||||
public EpisodesFragment() {
|
||||
|
@ -46,11 +50,32 @@ public class EpisodesFragment extends Fragment {
|
|||
toolbar.setTitle(R.string.episodes_label);
|
||||
((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
|
||||
viewPager = rootView.findViewById(R.id.viewpager);
|
||||
viewPager.setAdapter(new EpisodesPagerAdapter());
|
||||
viewPager.setAdapter(new EpisodesPagerAdapter(this));
|
||||
|
||||
// Give the TabLayout the ViewPager
|
||||
tabLayout = rootView.findViewById(R.id.sliding_tabs);
|
||||
tabLayout.setupWithViewPager(viewPager);
|
||||
|
||||
new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> {
|
||||
switch (position) {
|
||||
case POS_NEW_EPISODES:
|
||||
tab.setText(R.string.new_episodes_label);
|
||||
break;
|
||||
case POS_ALL_EPISODES:
|
||||
tab.setText(R.string.all_episodes_short_label);
|
||||
break;
|
||||
case POS_FAV_EPISODES:
|
||||
tab.setText(R.string.favorite_episodes_label);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}).attach();
|
||||
|
||||
// restore our last position
|
||||
SharedPreferences prefs = getActivity().getSharedPreferences(TAG, Context.MODE_PRIVATE);
|
||||
int lastPosition = prefs.getInt(PREF_LAST_TAB_POSITION, 0);
|
||||
viewPager.setCurrentItem(lastPosition, false);
|
||||
|
||||
return rootView;
|
||||
}
|
||||
|
||||
|
@ -64,52 +89,29 @@ public class EpisodesFragment extends Fragment {
|
|||
editor.apply();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
static class EpisodesPagerAdapter extends FragmentStateAdapter {
|
||||
|
||||
// restore our last position
|
||||
SharedPreferences prefs = getActivity().getSharedPreferences(TAG, Context.MODE_PRIVATE);
|
||||
int lastPosition = prefs.getInt(PREF_LAST_TAB_POSITION, 0);
|
||||
viewPager.setCurrentItem(lastPosition);
|
||||
}
|
||||
|
||||
public class EpisodesPagerAdapter extends FragmentPagerAdapter {
|
||||
|
||||
public EpisodesPagerAdapter() {
|
||||
super(getChildFragmentManager());
|
||||
EpisodesPagerAdapter(@NonNull Fragment fragment) {
|
||||
super(fragment);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public Fragment getItem(int position) {
|
||||
@Override
|
||||
public Fragment createFragment(int position) {
|
||||
switch (position) {
|
||||
case 0:
|
||||
case POS_NEW_EPISODES:
|
||||
return new NewEpisodesFragment();
|
||||
case 1:
|
||||
case POS_ALL_EPISODES:
|
||||
return new AllEpisodesFragment();
|
||||
default:
|
||||
case POS_FAV_EPISODES:
|
||||
return new FavoriteEpisodesFragment();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
public int getItemCount() {
|
||||
return TOTAL_COUNT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getPageTitle(int position) {
|
||||
switch (position) {
|
||||
case POS_ALL_EPISODES:
|
||||
return getString(R.string.all_episodes_short_label);
|
||||
case POS_NEW_EPISODES:
|
||||
return getString(R.string.new_episodes_label);
|
||||
case POS_FAV_EPISODES:
|
||||
return getString(R.string.favorite_episodes_label);
|
||||
default:
|
||||
return super.getPageTitle(position);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,7 +83,6 @@ public abstract class EpisodesListFragment extends Fragment {
|
|||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
setHasOptionsMenu(true);
|
||||
EventBus.getDefault().register(this);
|
||||
loadItems();
|
||||
}
|
||||
|
@ -91,6 +90,7 @@ public abstract class EpisodesListFragment extends Fragment {
|
|||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
setHasOptionsMenu(true);
|
||||
registerForContextMenu(recyclerView);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,29 +7,30 @@ import android.view.MenuInflater;
|
|||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentStatePagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.CastEnabledActivity;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.core.event.FeedItemEvent;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.core.util.Flavors;
|
||||
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
|
||||
/**
|
||||
* Displays information about a list of FeedItems.
|
||||
|
@ -41,7 +42,7 @@ public class ItemPagerFragment extends Fragment {
|
|||
/**
|
||||
* Creates a new instance of an ItemPagerFragment.
|
||||
*
|
||||
* @param feeditems The IDs of the FeedItems that belong to the same list
|
||||
* @param feeditems The IDs of the FeedItems that belong to the same list
|
||||
* @param feedItemPos The position of the FeedItem that is currently shown
|
||||
* @return The ItemFragment instance
|
||||
*/
|
||||
|
@ -76,31 +77,21 @@ public class ItemPagerFragment extends Fragment {
|
|||
feedItems = getArguments().getLongArray(ARG_FEEDITEMS);
|
||||
int feedItemPos = getArguments().getInt(ARG_FEEDITEM_POS);
|
||||
|
||||
ViewPager pager = layout.findViewById(R.id.pager);
|
||||
ViewPager2 pager = layout.findViewById(R.id.pager);
|
||||
// FragmentStatePagerAdapter documentation:
|
||||
// > When using FragmentStatePagerAdapter the host ViewPager must have a valid ID set.
|
||||
// When opening multiple ItemPagerFragments by clicking "item" -> "visit podcast" -> "item" -> etc,
|
||||
// the ID is no longer unique and FragmentStatePagerAdapter does not display any pages.
|
||||
int newId = ViewCompat.generateViewId();
|
||||
pager.setId(newId);
|
||||
pager.setAdapter(new ItemPagerAdapter());
|
||||
pager.setCurrentItem(feedItemPos);
|
||||
pager.setAdapter(new ItemPagerAdapter(this));
|
||||
pager.setCurrentItem(feedItemPos, false);
|
||||
loadItem(feedItems[feedItemPos]);
|
||||
pager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
|
||||
}
|
||||
|
||||
pager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
loadItem(feedItems[position]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
EventBus.getDefault().register(this);
|
||||
|
@ -173,20 +164,20 @@ public class ItemPagerFragment extends Fragment {
|
|||
((MainActivity) getActivity()).loadChildFragment(fragment);
|
||||
}
|
||||
|
||||
private class ItemPagerAdapter extends FragmentStatePagerAdapter {
|
||||
private class ItemPagerAdapter extends FragmentStateAdapter {
|
||||
|
||||
ItemPagerAdapter() {
|
||||
super(getFragmentManager(), BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
|
||||
ItemPagerAdapter(@NonNull Fragment fragment) {
|
||||
super(fragment);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
public Fragment createFragment(int position) {
|
||||
return ItemFragment.newInstance(feedItems[position]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
public int getItemCount() {
|
||||
return feedItems.length;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,13 +4,17 @@ import android.os.Bundle;
|
|||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentPagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.google.android.material.tabs.TabLayoutMediator;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
|
||||
/**
|
||||
|
@ -18,6 +22,11 @@ import de.danoeh.antennapod.R;
|
|||
*/
|
||||
public class GpodnetMainFragment extends Fragment {
|
||||
|
||||
private static final int NUM_PAGES = 2;
|
||||
private static final int POS_TOPLIST = 0;
|
||||
private static final int POS_TAGS = 1;
|
||||
private static final int POS_SUGGESTIONS = 2;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
super.onCreateView(inflater, container, savedInstanceState);
|
||||
|
@ -26,63 +35,59 @@ public class GpodnetMainFragment extends Fragment {
|
|||
toolbar.setTitle(R.string.gpodnet_main_label);
|
||||
((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
|
||||
|
||||
ViewPager viewPager = root.findViewById(R.id.viewpager);
|
||||
GpodnetPagerAdapter pagerAdapter = new GpodnetPagerAdapter(getChildFragmentManager());
|
||||
ViewPager2 viewPager = root.findViewById(R.id.viewpager);
|
||||
GpodnetPagerAdapter pagerAdapter = new GpodnetPagerAdapter(this);
|
||||
viewPager.setAdapter(pagerAdapter);
|
||||
|
||||
// Give the TabLayout the ViewPager
|
||||
TabLayout tabLayout = root.findViewById(R.id.sliding_tabs);
|
||||
tabLayout.setupWithViewPager(viewPager);
|
||||
|
||||
new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> {
|
||||
switch (position) {
|
||||
case POS_TAGS:
|
||||
tab.setText(R.string.gpodnet_taglist_header);
|
||||
break;
|
||||
case POS_TOPLIST:
|
||||
tab.setText(R.string.gpodnet_toplist_header);
|
||||
break;
|
||||
default:
|
||||
case POS_SUGGESTIONS:
|
||||
tab.setText(R.string.gpodnet_suggestions_header);
|
||||
break;
|
||||
}
|
||||
}).attach();
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
public class GpodnetPagerAdapter extends FragmentPagerAdapter {
|
||||
private static final int NUM_PAGES = 2;
|
||||
private static final int POS_TOPLIST = 0;
|
||||
private static final int POS_TAGS = 1;
|
||||
private static final int POS_SUGGESTIONS = 2;
|
||||
public static class GpodnetPagerAdapter extends FragmentStateAdapter {
|
||||
|
||||
public GpodnetPagerAdapter(FragmentManager fm) {
|
||||
super(fm);
|
||||
GpodnetPagerAdapter(@NonNull Fragment fragment) {
|
||||
super(fragment);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Fragment getItem(int i) {
|
||||
public Fragment createFragment(int position) {
|
||||
Bundle arguments = new Bundle();
|
||||
arguments.putBoolean(PodcastListFragment.ARGUMENT_HIDE_TOOLBAR, true);
|
||||
switch (i) {
|
||||
switch (position) {
|
||||
case POS_TAGS:
|
||||
return new TagListFragment();
|
||||
case POS_TOPLIST:
|
||||
PodcastListFragment topListFragment = new PodcastTopListFragment();
|
||||
topListFragment.setArguments(arguments);
|
||||
return topListFragment;
|
||||
default:
|
||||
case POS_SUGGESTIONS:
|
||||
PodcastListFragment suggestionsFragment = new SuggestionListFragment();
|
||||
suggestionsFragment.setArguments(arguments);
|
||||
return suggestionsFragment;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getPageTitle(int position) {
|
||||
switch (position) {
|
||||
case POS_TAGS:
|
||||
return getString(R.string.gpodnet_taglist_header);
|
||||
case POS_TOPLIST:
|
||||
return getString(R.string.gpodnet_toplist_header);
|
||||
case POS_SUGGESTIONS:
|
||||
return getString(R.string.gpodnet_suggestions_header);
|
||||
default:
|
||||
return super.getPageTitle(position);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
public int getItemCount() {
|
||||
return NUM_PAGES;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
package de.danoeh.antennapod.fragment.preferences;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentPagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.google.android.material.tabs.TabLayoutMediator;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.PreferenceActivity;
|
||||
|
@ -29,25 +29,35 @@ public class StatisticsFragment extends Fragment {
|
|||
|
||||
|
||||
private TabLayout tabLayout;
|
||||
private ViewPager viewPager;
|
||||
private ViewPager2 viewPager;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
super.onCreateView(inflater, container, savedInstanceState);
|
||||
setHasOptionsMenu(true);
|
||||
|
||||
View rootView = inflater.inflate(R.layout.pager_fragment, container, false);
|
||||
viewPager = rootView.findViewById(R.id.viewpager);
|
||||
viewPager.setAdapter(new StatisticsPagerAdapter(getChildFragmentManager(), getResources()));
|
||||
|
||||
viewPager.setAdapter(new StatisticsPagerAdapter(this));
|
||||
// Give the TabLayout the ViewPager
|
||||
tabLayout = rootView.findViewById(R.id.sliding_tabs);
|
||||
tabLayout.setupWithViewPager(viewPager);
|
||||
new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> {
|
||||
switch (position) {
|
||||
case POS_LISTENED_HOURS:
|
||||
tab.setText(R.string.playback_statistics_label);
|
||||
break;
|
||||
case POS_SPACE_TAKEN:
|
||||
tab.setText(R.string.download_statistics_label);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}).attach();
|
||||
|
||||
rootView.findViewById(R.id.toolbar).setVisibility(View.GONE);
|
||||
|
||||
|
@ -60,39 +70,27 @@ public class StatisticsFragment extends Fragment {
|
|||
((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.statistics_label);
|
||||
}
|
||||
|
||||
public static class StatisticsPagerAdapter extends FragmentPagerAdapter {
|
||||
public static class StatisticsPagerAdapter extends FragmentStateAdapter {
|
||||
|
||||
private final Resources resources;
|
||||
|
||||
public StatisticsPagerAdapter(FragmentManager fm, Resources resources) {
|
||||
super(fm);
|
||||
this.resources = resources;
|
||||
StatisticsPagerAdapter(@NonNull Fragment fragment) {
|
||||
super(fragment);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
if (position == 0) {
|
||||
return new PlaybackStatisticsFragment();
|
||||
} else {
|
||||
return new DownloadStatisticsFragment();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return TOTAL_COUNT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getPageTitle(int position) {
|
||||
public Fragment createFragment(int position) {
|
||||
switch (position) {
|
||||
case POS_LISTENED_HOURS:
|
||||
return resources.getString(R.string.playback_statistics_label);
|
||||
case POS_SPACE_TAKEN:
|
||||
return resources.getString(R.string.download_statistics_label);
|
||||
return new PlaybackStatisticsFragment();
|
||||
default:
|
||||
return super.getPageTitle(position);
|
||||
case POS_SPACE_TAKEN:
|
||||
return new DownloadStatisticsFragment();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return TOTAL_COUNT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Copyright 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Source: https://github.com/android/views-widgets-samples/blob/87e58d1/ViewPager2/app/src/main/java/androidx/viewpager2/integration/testapp/NestedScrollableHost.kt
|
||||
* And modified for our need
|
||||
*/
|
||||
|
||||
package de.danoeh.antennapod.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewParent;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
|
||||
import static androidx.viewpager2.widget.ViewPager2.ORIENTATION_HORIZONTAL;
|
||||
import static androidx.viewpager2.widget.ViewPager2.ORIENTATION_VERTICAL;
|
||||
|
||||
/**
|
||||
* Layout to wrap a scrollable component inside a ViewPager2. Provided as a solution to the problem
|
||||
* where pages of ViewPager2 have nested scrollable elements that scroll in the same direction as
|
||||
* ViewPager2. The scrollable element needs to be the immediate and only child of this host layout.
|
||||
*
|
||||
* <p>This solution has limitations when using multiple levels of nested scrollable elements
|
||||
* (e.g. a horizontal RecyclerView in a vertical RecyclerView in a horizontal ViewPager2).
|
||||
*/
|
||||
class NestedScrollableHost extends FrameLayout {
|
||||
|
||||
public NestedScrollableHost(@NonNull Context context) {
|
||||
super(context);
|
||||
touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
|
||||
}
|
||||
|
||||
public NestedScrollableHost(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
|
||||
}
|
||||
|
||||
private int touchSlop = 0;
|
||||
private float initialX = 0f;
|
||||
private float initialY = 0f;
|
||||
|
||||
private ViewPager2 getParentViewPager() {
|
||||
View v = (View) getParent();
|
||||
while (v != null && !(v instanceof ViewPager2)) {
|
||||
v = (View) v.getParent();
|
||||
}
|
||||
return v == null ? null : (ViewPager2) v;
|
||||
}
|
||||
|
||||
public boolean onInterceptTouchEvent(MotionEvent e) {
|
||||
ViewPager2 parentViewPager = getParentViewPager();
|
||||
if (parentViewPager == null) {
|
||||
return super.onInterceptTouchEvent(e);
|
||||
}
|
||||
|
||||
ViewParent parent = getParent();
|
||||
int orientation = parentViewPager.getOrientation();
|
||||
|
||||
if (e.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
initialX = e.getX();
|
||||
initialY = e.getY();
|
||||
parent.requestDisallowInterceptTouchEvent(true);
|
||||
} else if (e.getAction() == MotionEvent.ACTION_MOVE) {
|
||||
int dx = (int) (e.getX() - initialX);
|
||||
int dy = (int) (e.getY() - initialY);
|
||||
boolean isVpHorizontal = orientation == ORIENTATION_HORIZONTAL;
|
||||
|
||||
// assuming ViewPager2 touch-slop is 2x touch-slop of child
|
||||
float scaledDx = Math.abs(dx) * (isVpHorizontal ? .5f : 1f);
|
||||
float scaledDy = Math.abs(dy) * (isVpHorizontal ? 1f : .5f);
|
||||
if (scaledDx > touchSlop || scaledDy > touchSlop) {
|
||||
int value = isVpHorizontal ? dy : dx;
|
||||
if (isVpHorizontal == (scaledDy > scaledDx)) {
|
||||
// Gesture is perpendicular
|
||||
orientation = orientation == ORIENTATION_VERTICAL
|
||||
? ORIENTATION_HORIZONTAL : ORIENTATION_VERTICAL;
|
||||
value = isVpHorizontal ? dy : dx;
|
||||
}
|
||||
|
||||
int direction = (int) -Math.copySign(1, value);
|
||||
View child = getChildAt(0);
|
||||
if (orientation == ORIENTATION_HORIZONTAL) {
|
||||
parent.requestDisallowInterceptTouchEvent(child.canScrollHorizontally(direction));
|
||||
} else {
|
||||
parent.requestDisallowInterceptTouchEvent(child.canScrollVertically(direction));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.onInterceptTouchEvent(e);
|
||||
}
|
||||
}
|
|
@ -1,15 +1,20 @@
|
|||
package de.danoeh.antennapod.view;
|
||||
|
||||
import android.animation.ArgbEvaluator;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.database.DataSetObserver;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.vectordrawable.graphics.drawable.ArgbEvaluator;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import androidx.core.text.TextUtilsCompat;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public class PagerIndicatorView extends View {
|
||||
private final Paint paint = new Paint();
|
||||
|
@ -38,26 +43,31 @@ public class PagerIndicatorView extends View {
|
|||
paint.setAntiAlias(true);
|
||||
paint.setStyle(Paint.Style.FILL);
|
||||
|
||||
int[] colorAttrs = new int[] { android.R.attr.textColorSecondary };
|
||||
int[] colorAttrs = new int[]{android.R.attr.textColorSecondary};
|
||||
TypedArray a = getContext().obtainStyledAttributes(colorAttrs);
|
||||
circleColorHighlight = a.getColor(0, 0xffffffff);
|
||||
circleColor = (Integer) new ArgbEvaluator().evaluate(0.8f, 0x00ffffff, circleColorHighlight);
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
public void setViewPager(ViewPager pager) {
|
||||
numPages = pager.getAdapter().getCount();
|
||||
pager.getAdapter().registerDataSetObserver(new DataSetObserver() {
|
||||
public void setViewPager(ViewPager2 pager) {
|
||||
numPages = pager.getAdapter().getItemCount();
|
||||
pager.getAdapter().registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
|
||||
@Override
|
||||
public void onChanged() {
|
||||
numPages = pager.getAdapter().getCount();
|
||||
numPages = pager.getAdapter().getItemCount();
|
||||
invalidate();
|
||||
}
|
||||
});
|
||||
pager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
|
||||
boolean isLocaleRtl = TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault())
|
||||
== ViewCompat.LAYOUT_DIRECTION_RTL;
|
||||
pager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
PagerIndicatorView.this.position = position + positionOffset;
|
||||
if (isLocaleRtl) {
|
||||
PagerIndicatorView.this.position = numPages - 1 - PagerIndicatorView.this.position;
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
tools:background="@android:color/holo_green_light"
|
||||
android:elevation="8dp"/>
|
||||
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/pager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
|
|
|
@ -171,12 +171,18 @@
|
|||
|
||||
</LinearLayout>
|
||||
|
||||
<de.danoeh.antennapod.view.ShownotesWebView
|
||||
android:id="@+id/webvDescription"
|
||||
android:layout_width="match_parent"
|
||||
<de.danoeh.antennapod.view.NestedScrollableHost
|
||||
android:layout_below="@id/header"
|
||||
android:layout_height="match_parent"
|
||||
android:foreground="?android:windowContentOverlay" />
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<de.danoeh.antennapod.view.ShownotesWebView
|
||||
android:id="@+id/webvDescription"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:foreground="?android:windowContentOverlay" />
|
||||
|
||||
</de.danoeh.antennapod.view.NestedScrollableHost>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
app:navigationIcon="?homeAsUpIndicator"
|
||||
android:id="@+id/toolbar"/>
|
||||
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/pager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
|
|
@ -1,11 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.core.widget.NestedScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="false">
|
||||
<de.danoeh.antennapod.view.ShownotesWebView
|
||||
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="false">
|
||||
|
||||
<de.danoeh.antennapod.view.NestedScrollableHost
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<de.danoeh.antennapod.view.ShownotesWebView
|
||||
android:id="@+id/webview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</de.danoeh.antennapod.view.NestedScrollableHost>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
|
@ -21,9 +21,9 @@
|
|||
app:tabMode="fixed"
|
||||
app:tabGravity="fill"/>
|
||||
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/viewpager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
app:tabGravity="fill"
|
||||
app:tabMode="fixed" />
|
||||
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/viewpager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0px"
|
||||
|
|
Loading…
Reference in New Issue