How to loop (from last fragment to first) in a FragmentStatePagerAdapter - java

I've written this class that extends FragmentStatePagerAdapter in order to swipe between views. Now I need to make the swiping list circular so that swiping after the last fragment would display the first fragment. I haven't found a way to properly do that, any help?
Here's the code of the adapter:
public class DetailsPagerAdapter extends FragmentStatePagerAdapter {
List<Detail> details=null;
public DetailsPagerAdapter(FragmentManager supportFragmentManager, List<Detail> details) {
super(supportFragmentManager);
this.details=details;
}
#Override
public Fragment getItem(int i) {
System.out.println("Fetching item at position "+i);
Fragment fragment = new DetailsFragment();
Bundle args = new Bundle();
args.putString("img",details.get(i).getImageFileName());
args.putString("desc",details.get(i).getDescription());
fragment.setArguments(args);
return fragment;
}
public int getCount() {
return details.size();
}
}

in your Adapter, try something like that
#Override
public Fragment getItem(int pos) {
pos = pos % details.size();
....
}
#Override
public int getCount() {
return 99999;
}

Related

How to hide fragment from activity - Android Studio

I have two fragment in one activity, and I need to know how to just hide the second fragment and leave the firs one
So, i want to hide PerfilDatosFragmen();, but i also need to keep "2" in return statement. how can i do that?
public class ViewPagerAdapter extends FragmentStatePagerAdapter {
public ViewPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
String[] encabezado = {"Tarjeta", "Datos"};
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new PerfilTarjetaFragment();
case 1:
return new PerfilDatosFragmen();
}
return null;
}
#Override
public int getCount() {
System.out.println(vacio);
// int vacio = getIntent().getExtras().getInt("AcompaƱante");
/* if(vacio.equals("1")){
a= 1;
}else{
a= 2;
}*/
return 2;
}
It's very simple. PagerAdapter.getCount() is defined the count of your fragments. You always return 2. The best solution is:
public class ViewPagerAdapter extends FragmentStatePagerAdapter {
private final List<Fragment> fragments = new ArrayList<>();
public ViewPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
fragments.add(new PerfilTarjetaFragment());
fragments.add(new PerfilDatosFragmen());
}
String[] encabezado = {"Tarjeta", "Datos"};
#Override
public Fragment getItem(int position) {
return fragments.get(position);
}
#Override
public int getCount() {
return fragments.size();
}

getting NullPointerException error view pager while fetching fragment method in view pager Activity

I know this is very general question but can't able to figure out what is wrong.
Fragment java class
// newInstance constructor for creating fragment with arguments
public static BpDetails newInstance(int page) {
BpDetails fragmentFirst = new BpDetails();
Bundle args = new Bundle();
args.putInt("someInt", page);
fragmentFirst.setArguments(args);
return fragmentFirst;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
page = getArguments().getInt("someInt", 0);
}
public String getSystolic(){
return this.systolic.getText().toString();
}
/* public String getDiastolic(){
return this.diastolic.getText().toString();
}*/
// Inflate the view for the fragment based on layout XML
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.bp_details, container, false);
Log.i("View ",view.toString());
Log.i("DOB is ",Long.toString(Constants.dob));
systolic =(EditText) view.findViewById(R.id.systolic);
diastolic =(EditText) view.findViewById(R.id.diastolic);
return view;
}
ViewPager Activity
vpPager = (ViewPager) findViewById(R.id.view_pager);
adapterViewPager = new MyPagerAdapter(getSupportFragmentManager());
vpPager.setAdapter(adapterViewPager);
findViewById(R.id.btn_prev).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// checking for last page
// if last page home screen will be launched
int current = getItem(-1);
if (current!=0)
prevPage=current-1;
if (current < 4) {
// move to next screen
vpPager.setCurrentItem(current);
} else {
//final reached.
}
}
});
findViewById(R.id.btn_next).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// checking for last page
// if last page home screen will be launched
int current = getItem(+1);
if (current!=0)
prevPage=current-1;
System.out.println("Prev page "+prevPage);
if (current < 4) {
// move to next screen
Fragment bpFragment=adapterViewPager.getItem(vpPager.getCurrentItem());
if (bpFragment instanceof BpDetails){
System.out.println("Current item is "+vpPager.getCurrentItem());
BpDetails fr = (BpDetails)adapterViewPager.getItem(vpPager.getCurrentItem());
**String systolicString = fr.getSystolic();** //error point
Log.i("Systolic is ",systolicString);
}
} else {
//final reached.
}
}
});
}
private int getItem(int i) {
return vpPager.getCurrentItem() + i;
}
public static class MyPagerAdapter extends FragmentPagerAdapter {
private static int NUM_ITEMS = 4;
private static int mSelectedPosition;
public MyPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
//mSelectedPosition=selectedPosition;
}
// Returns total number of pages
#Override
public int getCount() {
return NUM_ITEMS;
}
// Returns the fragment to display for that page
#Override
public Fragment getItem(int position) {
switch (position) {
case 0: // Fragment # 0 - This will show FirstFragment
return BasicDetails.newInstance(0);
case 1:
return BpDetails.newInstance(1);
case 2:
return BslDetails.newInstance(2);
case 3:
return Summary.newInstance(3);
default:
return null;
}
}
}
Why I am getting the nullpointerException since I am accessing the public method of fragment before going to the next fragment.
Before down voting please leave the reason of down voting so that I can improve the question.
EDit:
I got to know since I am calling the getitem() method thats why all the variable of fragment to null that why I am getting the nullpointerException. Is there any way I solve this problem.
you should rewrite your ViewPagerAdapter and store the retuened fragment
this is because every time you call getItem() function you return a new fragment,but only invoked by the viewpager itself the fragment will invoke oncreateView ,so the second time you call getItem did not initialize the systolic and thus lead to NUllPointerException
for reference:
public static class MyPagerAdapter extends FragmentPagerAdapter {
private static int NUM_ITEMS = 4;
private static int mSelectedPosition;
Map<Integer,Fragment> map= new HashMap<>();
public MyPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
//mSelectedPosition=selectedPosition;
}
// Returns total number of pages
#Override
public int getCount() {
return NUM_ITEMS;
}
// Returns the fragment to display for that page
#Override
public Fragment getItem(int position) {
Fragment f = map.get(position)
if(f!=null){
return f;
}
switch (position) {
case 0: // Fragment # 0 - This will show FirstFragment
f = BasicDetails.newInstance(0);
case 1:
f = return BpDetails.newInstance(1);
case 2:
f = return BslDetails.newInstance(2);
case 3:
f = return Summary.newInstance(3);
default:
return null;
}
map.put(postion,f);
return f;
}
}

Android - Save/restore state with FragmentStatePageAdapter

I made this class:
public class My_ViewPagerAdapter extends FragmentStatePagerAdapter {
private ArrayList<My_Fragment> fragments=new ArrayList<>();
private ArrayList<String> tabTitles=new ArrayList<>();
public My_ViewPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
return fragments.get(position);
}
#Override
public int getItemPosition(Object object) {
for (int i=0;i<fragments.size();i++){
Class<? extends My_Fragment> clazz= fragments.get(i).getClass();
if (clazz.isInstance(object)){
return i;
}
}
return POSITION_NONE;
}
#Override
public int getCount() {
return fragments.size();
}
public void addFragment(My_Fragment fragment, String tabTitle){
fragments.add(fragment);
tabTitles.add(tabTitle);
notifyDataSetChanged();
}
public void removeFragment(int position){
fragments.remove(position);
tabTitles.remove(position);
notifyDataSetChanged();
}
public My_Fragment getFragmentAtTab(int position){
return fragments.get(position);
}
#Override
public CharSequence getPageTitle(int position) {
return tabTitles.get(position);
}
}
I'm adding/removing fragments/tabs dynamically, and i want to save their state through configuration changes.
I implemented onSaveInstanceState():
int tabs=tabLayout.getTabCount();
for (int i=0;i<tabs;i++){
outState.putInt("TabsCount",tabs);
outState.putString("Tab_"+i,getTabTitle(i));
outState.putString("FragmentClassAtTab_"+i,my_viewPagerAdapter.getFragmentAtTab(i).getClass().getName());
}
and i implemented onRestoreInstanceState():
for (int i=0;i<tabs;i++){
try {
My_Fragment fragment= (My_Fragment) Class.forName(savedInstanceState.getString("FragmentClassAtTab_"+i)).newInstance();
addTab(fragment ,savedInstanceState.getString("Tab_"+i));
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
catch (InstantiationException e) {
e.printStackTrace();
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
}
addTab method is:
public void addTab(My_Fragment fragment, String title){
if (fragment!=null) my_viewPagerAdapter.addFragment(fragment,title);
tabLayout.addTab(tabLayout.newTab().setText(title));
}
THE PROBLEM:
Every fragment i add gets recreated "automatically" when configuration change occurs, so its constructor gets called everytime. onCreateView gets called on these instances and not on the ones recreated by my code.
I need onCreateView to get called on fragments instantiated in my tabs in order to set their listviews.
Fragments created "automatically" get replaced by new fragment instances through my onRestoreInstanceState method, but no onCreateView method gets called on these new instances.
I think i'm doing it wrong and maybe there is a better way to save tabs and fragments throught configuration changes... Any help is appreciated.
I once created something similar, which in my case looked like this:
public class DisplayPagerAdapter extends FragmentStatePagerAdapter {
private static final String TAG = "DisplayPagerAdapter";
SparseArray<DisplayFragment> registeredFragments = new SparseArray<DisplayFragment>();
private final Context context;
private final DisplayCoreModule display;
private final FragmentManager fm;
private boolean isAddOrRemoving;
public DisplayPagerAdapter(Context context, FragmentManager fm,
DisplayCoreModule display) {
super(fm);
this.context = context;
this.display = display;
this.fm = fm;
Log.d(TAG, "pages " + display.getPagesCount());
}
public void notifySizeChangingDataSetChange() {
isAddOrRemoving = true;
notifyDataSetChanged();
isAddOrRemoving = false;
}
#Override
public int getCount() {
int count = (display != null && display.getPagesCount() > 0) ? display
.getPagesCount() : 1;
return count;
}
#Override
public int getItemPosition(Object object) {
DisplayFragment frag = (DisplayFragment) object;
if (!display.containsPageId(frag.getPageId())) {
// this will update the 'no information' page with id -1
return POSITION_NONE;
}
if (isAddOrRemoving) {
// recreate all for simplicity
return POSITION_NONE;
}
return POSITION_UNCHANGED;
}
#Override
public Fragment getItem(int position) {
Log.d(TAG, "getItem " + position);
return DisplayFragment.newInstance(position);
}
#Override
public CharSequence getPageTitle(int position) {
if (display != null && display.getPagesCount() > 0) {
return context.getString(R.string.page) + " " + (position + 1);
} else {
return super.getPageTitle(position);
}
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
Log.d(TAG, "instantiateItem " + position);
DisplayFragment fragment = (DisplayFragment) super.instantiateItem(
container, position);
registeredFragments.put(position, fragment);
return fragment;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
Log.d(TAG, "destroyItem " + position);
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
public Fragment getRegisteredFragment(int position) {
return registeredFragments.get(position);
}
public SparseArray<DisplayFragment> getRegisteredFragments() {
return registeredFragments;
}
}
It has been a long time since I wrote this, so are not able to go into great detail.
However, the key thing to note (I would think), is that I have an external 'bookkeeper' (the DisplayCoreModule). Whenever the amount of fragments would change in DisplayCoreModule, I simply invoked notifySizeChangingDataSetChange() to make the FragmentStatePagerAdapter refresh content.
Regaring some of your problems, FragmentStatePagerAdapter will not invoke onCreateView of your fragments until they are displayed. Usually this means only three fragments: the one you currently look at and one from either side of that fragment.
Perhaps, come to think of it, the root of your problem is missing getItemPosition() with POSITION_NONE. Seem to recall that it was neccesarry for dynamic content to be updated. To make notifyDataSetChanged have a proper effect.
HACKY SOLUTION:
I simply modified my addTab method:
public void addTab(My_Fragment fragment, String title){
boolean createFragment=true;
if (getTabCount()>0){
//all tabs must have different names
for (int i=0;i<getTabCount();i++){
if (getTabTitle(i).equals(title)==true){
createFragment=false;
break;
}
}
}
if (createFragment && fragment!=null){
//this ensures that if a fragment of the same type already exists, that should be the one to be added, tabs are made of fragments of different classes, so there will be no problem while checking this.
for (Fragment f: my_activity.getSupportFragmentManager().getFragments()){
if (fragment.getClass().isInstance(f)){
my_viewPagerAdapter.addFragment((My_Fragment)f,title);
tabLayout.addTab(tabLayout.newTab().setText(title));
return;
}
}
my_viewPagerAdapter.addFragment(fragment,title);
tabLayout.addTab(tabLayout.newTab().setText(title));
}
}

Section Page Adapter getCurrentItem title

I have a tab layout with 4 instances of the same fragment but with differents data in the list. And i want to get the current page so i can change data using the title. The problem is that the :mViewPager.getCurrentItem()) method isn't always called.
In oncreateview i have :
jours2 = new ArrayList<>();
rv = (RecyclerView) rootView.findViewById(R.id.recyclerView);
rv.setLayoutManager(new LinearLayoutManager(getContext()));
adapter = new MyAdapter(jours2);
rv.setAdapter(adapter);
String test= mSectionsPagerAdapter.getPageTitle(mViewPager.getCurrentItem()).toString();
for (Cours c : jours)
{
if (c.jour==test)
{
jours2.add(c);
}
}
adapter.notifyDataSetChanged();
So i can i change my code so it always get the current item title.
SectionPageAdapter :
public class SectionsPagerAdapter extends FragmentPagerAdapter {
ArrayList<Fragment> fragments = new ArrayList<>();
ArrayList<String> titles = new ArrayList<>();
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
public void AddFragment(Fragment fragment,String title)
{
fragments.add(fragment);
titles.add(title);
}
#Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
// Return a PlaceholderFragment (defined as a static inner class below).
return fragments.get(position);
}
#Override
public int getCount() {
// Show 3 total pages.
return fragments.size();
}
#Override
public CharSequence getPageTitle(int position) {
return titles.get(position);
}
}
You can either use this to get the position
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
tab.getPosition();
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
or you can simply use tabLayout.getSelectedTabPosition().

ViewPager get fragment reference

I have activity where I have created a viewpager that contains two fragments. I need to get a reference to the existing fragment or it's view, in the activity to refresh the list from the fragment if necessary. I was looking for a solution for two days, but found nothing on this occasion.
So here is my adapter
public class SearchPagerAdapter extends FragmentStatePagerAdapter {
CharSequence Titles[];
int NumbOfTabs;
public SearchPagerAdapter(FragmentManager fm,CharSequence mTitles[], int mNumbOfTabsumb) {
super(fm);
this.Titles = mTitles;
this.NumbOfTabs = mNumbOfTabsumb;
}
#Override
public Fragment getItem(int position) {
if(position == 0)
{
FragmentAyahSearch tab1 = new FragmentAyahSearch();
return tab1;
}
else
{
FragmentSurahList tab2 = new FragmentSurahList();
return tab2;
}
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
}
#Override
public CharSequence getPageTitle(int position) {
return Titles[position];
}
#Override
public int getCount() {
return NumbOfTabs;
}
}
below, I create a viewpager and adapter in MainActivity
searchAdapter = new SearchPagerAdapter(getSupportFragmentManager(), searchTitles, Numboftabs);
pager.setAdapter(searchAdapter);
tabs.setViewPager(pager);
I hope you will help me, because I'm losing my mind over this.
I would suggest maintain a list like
private List<Fragment> frag = new ArrayList<Fragment>();
then
public class SearchPagerAdapter extends FragmentStatePagerAdapter {
CharSequence Titles[];
int NumbOfTabs;
public SearchPagerAdapter(FragmentManager fm,CharSequence mTitles[], int mNumbOfTabsumb) {
super(fm);
this.Titles = mTitles;
this.NumbOfTabs = mNumbOfTabsumb;
}
#Override
public Fragment getItem(int position)
{
Fragment fragment = frag.get(position);
if(fragment == null )
{
if (position == 0)
{
fragment = new FragmentAyahSearch();
}
else
{
fragment = new FragmentSurahList();
}
}
return fragment;
}
#Override
public CharSequence getPageTitle(int position) {
return Titles[position];
}
#Override
public int getCount() {
return frag.size();
}
now if you want the reference of any fragment
just call , frag.get(<position>) will return you desire frgament

Categories

Resources