I have a simple FragmentPagerAdapter class
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
PagerAdapter fragment;
fragment = new PagerAdapter(data.get(position));
return fragment;
}
#Override
public int getCount() {
return data.size();
}
#Override
public CharSequence getPageTitle(int position) {
if (position >= pageCount || position < 0)
return null;
return "Profile " + position;
}
}
that PagerAdapter is a simple class that extends from Fragment.
and then I set an instance of SectionsPagerAdapter to my ViewPager.
problem is here:
at first I have one page on view pager( data size is 1), when I get more data , I call SectionsPagerAdapter instance notifyDataSetChanged, but in getItem(int position) method instead of position start form 0, it start from 1 !!!
what should I do? I wanna re creat my view pager after I get more data
Thanks in advance
You needed to set the adapter again to reset the position, notifyDataSetChanged is used to notify the adapter there is a data change so its rebind the data only.
Or You can use this code to move the view pager which position you want
viewPager.setCurrentItem(0);
notifyDataSetChanged() will only Notify any registered observers that the data set has changed regardless of touching viewPager positions.
There are two different classes of data change events, item changes
and structural changes. Item changes are when a single item has its
data updated but no positional changes have occurred. Structural
changes are when items are inserted, removed or moved within the data
set.
You have to set viewPager's position to start page(position 0) manually after notifyDataSetChanged().
adapter.notifyDataSetChanged();
viewPager.setCurrentItem(0);
Related
I have a ViewPager and ViewPagerAdapter as defined below:
private static class ViewPagerAdapter extends FragmentPagerAdapter {
#Override
public int getCount() {
return fragments.size();
}
#Override
public Fragment getItem(int position) {
return fragments.get(position);
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
}
Within my activity I am populating fragments array which is my list of Fragments which I can view by scrolling horizontally:
// populate fragments
fragments.add(....);
pager_adapter = new ViewPagerAdapter(getSupportFragmentManager());
view_pager.setAdapter(pager_adapter);
All this works fine. But, now I have a situation where in at run time I have to add one more fragment to this list and then refresh the view so that the new fragments becomes visible too upon scrolling. For this I added the following code inside my activity:
public static void addPageAndRefresh(Page page) {
fragments.add(PinFragment.newInstance(fragments.size(), true, page, book, false, false, null));
pager_adapter.notifyDataSetChanged();
}
After this, I do get a new fragment, but it is not the one which I added, its a copy of the last fragment in the last before calling notifyDataSetChanged().
Is this the correct way of doing this? It looks like although the fragments array is updated properly, but the view is not picking up the updated array. But, if it isn't then I shouldn't be seeing the new fragment after scrolling.
I tried similar requirement as yours with a FragmentStatePagerAdapter which worked fine. May be you would want to try it.
To add the new fragment:
SIZE = SIZE +1;
adapter.instantiateItem(viewPager, SIZE-1);
adapter.notifyDataSetChanged();
In getItem(), for the "position" create and return the new fragment (I used a switch statement here)
Update the getCount() method to return the new SIZE.
Let me know if you would like me to share the code.
I want to use ViewPager to swipe through songs in my Media Player ( going forward or backward like SoundCloud app for android ).
I have created a fragment which I inflate and set inside information like song name, author etc.
I have read some topics on StackOverflow about the ViewPager displays wrong items ( Viewpager shows wrong page and Android Viewpager show wrong pages and a lot more ) but I don't have fixed number of XML's to use with the ViewPager.
My Data is displayed in a RecyclerView, when I am pressing the item on index 4 for example I call the following method:
mPager.setCurrentItem(position);
So the mPager is set to position 4.
#Override
public Fragment getItem(int position) {
Log.i("TEST","Returnin a fragment on position "+position);
return fragment = new MusicSliderFragment();
}
But on my Adapter when it's changing I get the following output:
02-23 10:39:57.131 7599-7599/************** I/TEST: Returning a fragment on position 4
02-23 10:39:57.131 7599-7599/************** I/TEST: Returning a fragment on position 3
02-23 10:39:57.131 7599-7599/************** I/TEST: Returning a fragment on position 5
And when my application is launched I get the following output:
I/TEST: Returning a fragment on position 0
I/TEST: Returning a fragment on position 1
The main problem is when I am opening the app first time and set the song on position 4 the fragment information are displayed in the next fragment.
Is there a way how can I fix this?
Adapter Class:
private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
private MusicSliderFragment fragment;
public ScreenSlidePagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
Log.i("TEST","Returnin a fragment on position "+position);
return fragment = new MusicSliderFragment();
}
#Override
public int getCount() {
return NUM_PAGES;
}
public void updateSongName(String name) {
fragment.setSongName(name);
}
}
The RecyclerView Listener :
musicList.addOnItemTouchListener(
new RecyclerItemClickListener(getApplicationContext(), new RecyclerItemClickListener.OnItemClickListener() {
#Override
public void onItemClick(View view, final int position) {
Log.i("TEST", "Setting the mPager position to: "+position);
mPager.setCurrentItem(position);
}
}
And the `Listener` of the `mPager` where I update the song name for example:
mPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
play(position);
ScreenSlidePagerAdapter adapter = (ScreenSlidePagerAdapter) mPager.getAdapter();
adapter.updateSongName(splitName(myDataList.get(position))[0]);
Log.i("TEST", "Playing the position: "+position);
mPagerAdapter.notifyDataSetChanged();
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
View pager can load neighbour fragments when you choose current. Method setOffscreenPageLimit() defines how many neighbours you want to preload.
onPageSelected(int position) should work correct and returns current item.
Viewpager indexing starts from zero if you want to load the fourth Fragment then you need to set the position 3.
mPager.setCurrentItem(3); //Load the 4th fragment according to you.(0-3)
I have built an application with a navbar on the left, whose main content is a ViewPager
The ViewPager slides between two different views.
When the user selects something from the navgation bar, I send a message to the ViewPager's adapter (I have tried both FragmentPagerAdapter and FragmentStatePagerAdapter for this, both won't work) which sets an internal variable and calls notifyDatasetChanged();
The problem is that the getCount() method always returns 2 , so when the adapter checks to see if the dataset has changed, it sees that the items are still 2 and does not go on to call getItem(position).
The getItem(position) returns different fragments according to the value of the internal variable that is set before notifyDatasetChanged();
I tried overriding getItemId(position) in case the pager checks for the id, but it seems to not bother after checking the count.
Is there a way to force the adapter to rebuild the fragments when notifyDatasetChanged() is called?
Thanks in advance for any help you can provide
Edit: here is the code I am currently using:
public class ContentAdapter extends FragmentPagerAdapter {
private ViewedSection _section = ViewedSection.Main;
public ContentAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
ViewedScreen screen = get_screen(position);
return screen == null ? null : FragmentFactory.GetFragment(get_screen(position));
}
#Override
public int getCount() {
return 2;
}
private ViewedScreen get_screen(int position) {
//code to resolve which screen will be shown according to the current position and _section
}
public void set_page(ViewedSection section) {
this._section = section;
notifyDataSetChanged();
}
}
So when the user clicks on a NavBar item, I call ((ContentAdapter)_pager.getAdapter()).set_page(section);
For this, you need to override
public int getItemPosition (Object object)
Return POSITION_UNCHANGED if you don't want to replace the fragment. Return POSITION_NONE if you want to replace the fragment. (Also, you can return a new position to move the fragment to.)
A common override is
public int getItemPosition (Object object) {
return POSITION_NONE;
}
which will just rebuild everything.
I have a PagerAdapter with a dynamic number of elements. You can modify the number of tabs with a single call, which clears the list and the count to 0. Unfortunately, this does not remove the fragment that is currently showing.
public class MyPagerAdapter extends FragmentStatePagerAdapter {
private List<Pojo> pojos = new ArrayList<>;
#Override
public int getCount() {
return pojos.size();
}
public void removeAll() {
this.pojos.clear();
notifyDataSetChanged();
}
}
Does anyone know how to force the ViewPager to clear himself?
UPDATE 1:
If you use viewPager.removeAllViews() then the viewPager is unusable afterwards even after adapter notifies new data changes.
I have:
A ViewPager with a FragmentPagerAdapter on (or a FragmentStatePagerAdapter, doesn't really solve my problem).
A fixed number of fragments. They all share the same layout, but have TextViews that need to be set differently;
An AsyncTask that queries my database and retrieves content to be set into the TextViews.
So my code was:
public class StatsPagerAdapter extends FragmentPagerAdapter {
static final int FRAGMENT_COUNT = 5;
private Parameters[] sectionData;
public StatsPagerAdapter(FragmentManager manager) {
super(manager);
this.sectionData = new Parameters[FRAGMENT_COUNT];
}
#Override
public Fragment getItem(int position) {
return StatsSectionFragment.getInstance(this.sectionData[position]);
}
#Override
public int getCount() {
return FRAGMENT_COUNT;
}
public void setSectionData(int position, Parameters sectionData) {
this.sectionData[position] = sectionData;
notifyDataSetChanged();
}
}
So I'm passing sectionData[position] to the getInstance() method of my generic sub-fragment. That data should differentiate each instance of the fragments loaded into the ViewPager.
At first I'll be passing an empty reference, but then in my async class:
#Override
protected void onProgressUpdate(Parameters... sectionValues) {
super.onProgressUpdate(sectionValues);
mPagerAdapter.setSectionData(sectionId, sectionValues[0]);
}
That should call the setSectionData() above, update sectionData[position] and generate a call to notifiyDataSetChanged(). I was hoping that doing so would make the adapter retrieve all its items again, thus calling getItem() again, and loading new fragments.
Sadly it does not. So right now:
if fragments (i.e., getItem()) are created before my async task result are published, that item will stay empty (i.e.,visible fragment, but with empty text views since I never called getInstance(non-null stuff).
That happens for fragment 0 && fragment 1.
if fragments are created after my async task has ended (fragment 2 to end, because getItem() is called only when you reach that fragment by swiping), then the first and only call to getItem() produces a getInstance(non-null stuff), and that's ok.
How can I reload content into those already-there fragments, or force the adapter to call getItem() and update its views?
Add this to your adapter:
#Override
public int getItemPosition(Object object){
return PagerAdapter.POSITION_NONE;
}
This make your adapter call getItem again when you call notifyDataSetChanged();