In My application, I have used the ViewPager.
Like,
(say main.xml)
<android.support.v4.view.ViewPager
android:id="#+id/viewPager"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_above="#+id/register_header" />
And Create ViewPager object and ViewPagerAdapter(which extends FragmentPagerAdapter) object in FragmentActivity.
_mViewPager = (ViewPager) findViewById(R.id.viewPager);
_adapter = new ViewPagerAdapter(getApplicationContext(),
getSupportFragmentManager());
_mViewPager.setAdapter(_adapter);
And the Adapter class is like,
public class ViewPagerAdapter extends FragmentPagerAdapter {
private Context _context;
private FragmentManager manager;
private Fragment f;
private String classname="ViewPagerAdapter";
public ViewPagerAdapter(Context context, FragmentManager fm) {
super(fm);
_context=context;
manager=fm;
}
#Override
public Fragment getItem(int position) {
Log.i(classname,"getItem called"+position);
f = new Fragment();
f=MyFragment.newInstance();
Bundle args = new Bundle();
args.putInt("position", position);
f.setArguments(args);
return f;
}
#Override
public int getCount() {
return User.getPageCount();
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
}
And in MyFragment Class,
In onResume , I have to store the wigets object to the common static variable.
public void onResume() {
super.onResume();
pageIndex = getArguments().getInt("position");
User.useTextview1=textview1;
User.useTextview2= textview2;
User.current_pageIndex=pageIndex;
}
I have to update the textviews got from the User class in the FragmentActivity.
My Problem is getItem() method is called twice on First time
In Fact , the view displayed in the emulator is 0th index, but got 1st Index value in the FragmentActivity.
If I stopped the calling of getItem() method on second time, I can able to get the 0th index TextView reference in the FragmentActivity.
Please provide me the best way to do this.
Thanks
The FragmentPagerAdapter instantiates 2 Fragments on start, for index 0 and for index 1. If you want to get data from the Fragment which is on the screen, you can use setOnPageChangeListener for the Pager to get current position. Then have SparseArray with WeakReference to your fragments. Update that array in the getItem call. When onPageSelected gets called use that position to get reference to right Fragment and update User data.
Initialization of array:
private SparseArray<WeakReference<MyFragment>> mFragments = new SparseArray<WeakReference<MyFragment>>(3);
in getItem method i wrote this..
#Override
public Fragment getItem(int index) {
EditFragment frag = new EditFragment();
Bundle args = new Bundle();
args.putSerializable("currentItem", itemsList.get(index));
frag.setArguments(args);
return (frag);
}
here itemsList.get(index) is the model class object which i will use in EditFragment class.
here is that.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
View result = inflater.inflate(R.layout.pager_fragment_layout, container, false);
image = (ImageView)result.findViewById(R.id.pager_image);
text = (TextView)result.findViewById(R.id.pager_item_desc);
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getActivity()).build();
ImageLoader.getInstance().init(config);
imLoader = ImageLoader.getInstance();
****NOTE
final SwapItems itemList = (SwapItems) getArguments().getSerializable("currentItem");
imagePath = itemList.getPaths().get(0);
imLoader.displayImage(imagePath,image);
text.setText(itemList.getItemDescription());
image.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Fragment fragment = new ItemImagesFragment();
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Bundle bundle = new Bundle();
bundle.putSerializable("val", itemList);
fragment.setArguments(bundle);
fragmentTransaction.replace(R.id.content_frame, fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
});
return result;
}
NOTE: here i am getting swapitems model object from previous getItem method is 'final'. this solves my issue. Earlier i was initialized the same object with static as modifier.
hope yours will also clear
My Problem is getItem() method is called twice on First time
This is not the problem, this is default feature of FragmentPagerAdapter. Its good for you to swipe from this page to the next one and previous one.
the view displayed in the emulator is 0th index, but got 1st Index value in the FragmentActivity
I got the same issue, and I know why. This because you used same Fragment in View Pager.
How to fix this is separate Fragments by using different Fragment.
I faced the same issue - getItem() method was called twice. I don't know about your purposes of using that method by mine was to trigger changes in a hosting activity when new slide appears.
Well, first of all getItem() is not a right method to get event of appearing new slide.
I used ViewPager.OnPageChangeListener listener on ViewPager itself for this purpose.
Here is what I did:
In Activity that holds slide fragments:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.signature_wizard_activity);
// Instantiate a ViewPager and a PagerAdapter.
mPager = (ViewPager) findViewById(R.id.pager);
mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
mPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
onSlideChanged(position); // change color of the dots
}
#Override
public void onPageSelected(int position) {}
#Override
public void onPageScrollStateChanged(int state) {}
});
}
onPageScrolled() is called every time your slide appears, as a parameter it gets current position of the slide that is shown. Nice thing is that it is called including the first time it appears, not just when slide was changed.
When it can be used?
For example if you have some wizard activity with ViewPager where you slide fragments with some hints, you probable would like to have a bar with grey dots below the slider that would represent the number of slides in total, and one of the dots will be different color representing the current slide.
In this case ViewPager.OnPageChangeListener and method onPageScrolled() will be the best option.
Or if you have buttons PREV. and NEXT which change slides and you want to disable PREV. button on the first slide and disable NEXT button on the last slide. Here is how you do it inside onPageScrolled() method:
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if(position == 0){
prevBtn.setTextColor(ContextCompat.getColor(SignatureWizardActivity.this, R.color.main_grey_500));
prevBtn.setEnabled(false);
}else{
prevBtn.setTextColor(ContextCompat.getColor(SignatureWizardActivity.this, R.color.main_blue));
prevBtn.setEnabled(true);
}
if(position == NUM_PAGES -1){
nextBtn.setTextColor(ContextCompat.getColor(SignatureWizardActivity.this, R.color.main_grey_500));
nextBtn.setEnabled(false);
}else{
nextBtn.setTextColor(ContextCompat.getColor(SignatureWizardActivity.this, R.color.main_blue));
nextBtn.setEnabled(true);
}
}
where NUM_PAGES is a constant with total number of slides
you can use this method to update your views
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
// Fetch data or something...
}
}
Related
When I get a child view from items 0 to 2 in viewpager, it works fine. When I try to get a child view from 3 onward, it returns null. How can I get all the current selected child view of viewpager?
Edited:
View view = viewPager.getChildAt(viewPager.getCurrentItem());
When viewPager.getCurrentItem() reached 3 onward, the view return null.
You need to access the Fragments which you use in your ViewPager.
In this answer https://stackoverflow.com/a/39274141/1559852 i tried to explain how to modify your ViewPager's adapter o make the fragments which you use in your ViewPager accessible.
After you implemented the code in link, you'll be able to access your fragments and it's views.
Define a public method to your Fragments like below:
public View getMyFragmentView(){
return this.mView();
}
Finally add an OnPageChangeLsitener to your ViewPager like the following code.
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
// Here's your instance
final YourFragment fragment =(YourFragment)yourPagerAdapter.getRegisteredFragment(position);
final View theViewYouWantToAccess = yourFragment.getMyView();
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
Edit: In your ViewPager adapter you can register the Fragment to SparseArray
#Override
public Fragment getItem(int position) {
final YourFragment fragment = new YourFragment();
// Register your fragment to Sparse Array here
registeredFragments.put(position, fragment);
return fragment;
}
I have an activity with 3 fragments (A, B, C). Fragment A consists of a ViewPager with 2 ListFragments. The user can tap on an item in any of the listfragments and by doing so, goes to fragment B.
In fragment A I do:
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
pagerAdapter = new PagerAdapter(getActivity().getSupportFragmentManager());
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragmentA, container, false);
vpPager = (ViewPager)view.findViewById(R.id.vpPager);
vpPager.setOffscreenPageLimit(2);
vpPager.setAdapter(pagerAdapter);
vpPager.addOnPageChangeListener(this);
return view;
}
And the PagerAdapter is as follows:
private class PagerAdapter extends FragmentPagerAdapter {
private final ListFragment1 lf1 = ListFragment1 .newInstance();
private final ListFragment2 lf2 = ListFragment2 .newInstance();
public PagerAdapter(android.support.v4.app.FragmentManager fm) {
super(fm);
}
#Override
public android.support.v4.app.Fragment getItem(int position) {
switch (position) {
case 0: return lf1;
case 1: return lf2;
default: return null;
}
}
}
The first time the activity is shown, the viewpager list fragments are displayed correctly.
The 2 viewpager fragments load data from a db, and I do this only once (when the fragments are created).
The user can tap on an item and fragment B is displayed. If the user presses Back, fragment A is shown. However the list fragments are not shown (already an instance of them still exists).
Could it be that the view has been destroyed, even though instances exist?
What is wrong here? Is there a better approach?
EDIT
If I use newInstance in the pager adapter, I get an IllegalStateException: not attached to activity. This is because I start an async task as follows:
#Override
public void onPageSelected(int position) {
Fragment fragment = pagerAdapter.getItem(position);
if (fragment instanceof IPagedFragment) {
((IPagedFragment) fragment).onShown();
}
}
And onShown is:
#Override
public void onShown() {
myTask= new MyTask();
myTask.execute((Void)null);
}
When can I start the task so that I can be 100% sure that the fragment is attached to the activity and that the view has been created (I need to get listview, etc. from the layout).
You have to use ChildFragmentManager like below.
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
pagerAdapter = new PagerAdapter(getChildFragmentManager()); //here used child fragment manager
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragmentA, container, false);
vpPager = (ViewPager)view.findViewById(R.id.vpPager);
vpPager.setOffscreenPageLimit(2);
vpPager.setAdapter(pagerAdapter);
vpPager.addOnPageChangeListener(this);
return view;
}
It works like charm in my code with viewpager and fragment.
Just now I solved it after struggling for whole day, by using getChildFragmentManager()
pass this as a parameter to the pagerAdapter. and it will work.
while using pagerAdapter in fragment use :
PagerAdapter adapter = new PagerAdapter(getChildFragmentManager());
and in case of activity use getFragmentManager()
PagerAdapter adapter = new PagerAdapter(getFragmentManager());
You're creating ListFragment1 and ListFragment2 using the Activity FragmentManager, while you should use the Fragment FragmentManager. So, modify the pagerAdapter = new PagerAdapter(getActivity().getSupportFragmentManager()); with pagerAdapter = new PagerAdapter(getChildFragmentManager());. In this way, the fragments of the view pager will be 'bound' to the fragment hosting the viewpager. Moreover, you should not keep any reference to fragments inside the viewpager: it's something that Android already manage. Try with:
private class PagerAdapter extends FragmentPagerAdapter {
public PagerAdapter(android.support.v4.app.FragmentManager fm) {
super(fm);
}
#Override
public android.support.v4.app.Fragment getItem(int position) {
switch (position) {
case 0: return ListFragment1.newInstance();
case 1: return ListFragment2.newInstance();
default: return null;
}
}
}
By the way, the vpPager.setOffscreenPageLimit(2); is unuseful since you have just 2 pages and this is a method that I've never used even when I have many fragments to manage, since it requires memory.
About your update: remove any logic related to ViewPager handling the fragment. If you need to start an AsyncTask within your Fragment, you can do it using one of the methods of Fragment lifecycle: onResume(), onCreateView() and so on.
class IPagedFragment extends Fragment {
public void onResume() {
super.onResume();
myTask= new MyTask();
myTask.execute((Void)null);
}
}
and please, remove the private final ListFragment1 lf1 = ListFragment1 .newInstance();. Trust me, it's not a good idea since you have a strong reference to your Fragments.
I've built a simple project that you can use as reference implementation. You can download the source code from my dropbox.
use getChildFragmentManager() instead of supportFragmentManager()
If any of the solutions above doesn't work, you can try a workaround by posting (delayed) to the pager view instance an additional notifyDataSetChanged call of the adapter:
vpPager.post(new Runnable() {
#Override
public void run() {
pagerAdapter.notifyDataSetChanged();
}
});
or
vpPager.postDelayed(new Runnable() {
#Override
public void run() {
pagerAdapter.notifyDataSetChanged();
}
}, 100 /* you have to find out the best delay time by trying/adjusting */);
Try overriding the getItemPosition method in your FragmentPagerAdapter:
#Override
public int getItemPosition(Object object) {
return PagerAdapter.POSITION_NONE;
}
If you experience this with Kotlin, it will be like this.
val fragmentAdapter = FragmentPageAdapter(childFragmentManager)
You shouldn't keep references to fragments in your FragmentPagerAdapter. You should always call newInstance in getItem() call, for example:
#Override
public android.support.v4.app.Fragment getItem(int position) {
switch (position) {
case 0: return ListFragment1.newInstance();
case 1: return ListFragment2.newInstance();
default: return null;
}
}
The data you load from the database should be stored in the fragment itself. The adapter will restore the state of fragments (setOffscreenPageLimit(2)).
You are losing your fragments because the items (fragments) are instantiated by the FragmentManager you provide, and it creates fragments based on tags. So it can happen that it creates a new instance of the fragment you already keep, just with different tag.
See FragmentPagerAdapter source code (check instantiateItem() method):
https://android.googlesource.com/platform/frameworks/support/+/refs/heads/master/v13/java/android/support/v13/app/FragmentPagerAdapter.java
Also see this answer:
keep instances of fragments inside FragmentPagerAdapter
On PagerAdapter class override the method setPrimaryItem,
which is called when there's a change in the pager, i would give it a shot.
I would create something like :
private class PagerAdapter extends FragmentPagerAdapter {
private final ListFragment1 lf1 = ListFragment1 .newInstance();
private final ListFragment2 lf2 = ListFragment2 .newInstance();
public PagerAdapter(android.support.v4.app.FragmentManager fm) {
super(fm);
}
#Override
public android.support.v4.app.Fragment getItem(int position) {
switch (position) {
case 0: return lf1;
case 1: return lf2;
default: return null;
}
}
#Override
public int getCount() {
return 2;
}
#Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
super.setPrimaryItem(container, position, object);
if (position == 0)
lf1.updateUI(); //Refresh what you need on this fragment
else if (position == 1)
lf2.updateUI();
}
}
You're missing getCount() as well.
I'm not sure offscreen has any use, but its probably not an issue. vpPager.setOffscreenPageLimit(2)
One more thing, i would also remove vpPager.addOnPageChangeListener(this), there's no use for this, an it might cause you some issues.
Whatever you need to do, you can pull it off without it, by overriding the pagination, you might "ruin" some of the standard pagination(since the super isn't called)
I have seen a lot of answered questions about this, but none about what I exactly want so here it goes (if there's an answered thread about this I'd appreciate it):
I want to create a kind of "level selection" app, where you basically have to swipe from right to left in order to be able to see the next list of levels, however I want to do it WITHOUT tabs (haven't found out how to do it yet).
Thanks.
EDIT: Solved it by simply using a ViewPager without even bothering or paying attention to the ActionBar part Android tells you to add (I just created my few fragments, my viewpager, and this last one did the rest, didn't even need to use a gesture detector for swipes as viewpager already provides this animation).
Any ViewPager Tutorial teaching you how to swipe between tabs basically has all the information I needed :) Thanks everyone!
For doing this you shiuld use ViewPager
Its easy !
Layout ViewPager
<android.support.v4.view.ViewPager
android:id="#+id/vpPager"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</android.support.v4.view.ViewPager>
Define Fragments
public class FirstFragment extends Fragment {
// Store instance variables
private String title;
private int page;
// newInstance constructor for creating fragment with arguments
public static FirstFragment newInstance(int page, String title) {
FirstFragment fragmentFirst = new FirstFragment();
Bundle args = new Bundle();
args.putInt("someInt", page);
args.putString("someTitle", title);
fragmentFirst.setArguments(args);
return fragmentFirst;
}
// Store instance variables based on arguments passed
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
page = getArguments().getInt("someInt", 0);
title = getArguments().getString("someTitle");
}
// Inflate the view for the fragment based on layout XML
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_first, container, false);
TextView tvLabel = (TextView) view.findViewById(R.id.tvLabel);
tvLabel.setText(page + " -- " + title);
return view;
}
}
Setup FragmentPagerAdapter
public class MainActivity extends FragmentActivity {
// ...
public static class MyPagerAdapter extends FragmentPagerAdapter {
private static int NUM_ITEMS = 3;
public MyPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
// 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 FirstFragment.newInstance(0, "Page # 1");
case 1: // Fragment # 0 - This will show FirstFragment different title
return FirstFragment.newInstance(1, "Page # 2");
case 2: // Fragment # 1 - This will show SecondFragment
return SecondFragment.newInstance(2, "Page # 3");
default:
return null;
}
}
// Returns the page title for the top indicator
#Override
public CharSequence getPageTitle(int position) {
return "Page " + position;
}
}
}
Apply the Adapter
public class MainActivity extends FragmentActivity {
FragmentPagerAdapter adapterViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
ViewPager vpPager = (ViewPager) findViewById(R.id.vpPager);
adapterViewPager = new MyPagerAdapter(getSupportFragmentManager());
vpPager.setAdapter(adapterViewPager);
}
// ...
}
Setup OnPageChangeListener
// Attach the page change listener inside the activity
vpPager.setOnPageChangeListener(new OnPageChangeListener() {
// This method will be invoked when a new page becomes selected.
#Override
public void onPageSelected(int position) {
Toast.makeText(HomeActivity.this,
"Selected page position: " + position, Toast.LENGTH_SHORT).show();
}
// This method will be invoked when the current page is scrolled
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// Code goes here
}
// Called when the scroll state changes:
// SCROLL_STATE_IDLE, SCROLL_STATE_DRAGGING, SCROLL_STATE_SETTLING
#Override
public void onPageScrollStateChanged(int state) {
// Code goes here
}
});
if you need more info see this link (it also explain how to use tabs) :
https://github.com/codepath/android_guides/wiki/ViewPager-with-FragmentPagerAdapter
You have to use HorizontalScrollView (http://developer.android.com/reference/android/widget/HorizontalScrollView.html) which will manage horizontall scroll by himself. Juste place other view inside and you're good.
Edit: Solved it by simply using a ViewPager without even bothering or paying attention to the ActionBar part Android tells you to add (I just created my few fragments, my viewpager, and this last one did the rest, didn't even need to use a gesture detector for swipes as viewpager already provides this animation).
Any ViewPager Tutorial teaching you how to swipe between tabs basically has all the information I needed :) Thanks everyone!
I've got a FragmentActivity when I instantiate three different (n, n+1, n+2) Fragments.
I need to keep each Fragment updated when user swipes to it, so I used ViewPager.SimpleOnPageChangeListener.onPageSelected in the Fragment Activity, so when user swipes to n+1 or n+2 Fragment and again to n that function update the content.
Without using this workaround if I'm in the Fragment n+1, both n and n+2 are already loaded! I'd like instead that the Fragment load when the user swipes to it, without "pre-load".
This workaround works fine for me but it has a problem: the n Fragment that is the first in the list at start up of the app doesn't load its content. To load its content I have to swipe to n+1 then go back to n.
I know that the content of the Fragment should be setted on the class called at the moment of instantiate the fragment and that extends Fragment class, but in this way I don't know how to keep up to date each Fragment, as I do using onPageSelected.
Any suggestions?
EDIT 1:
I istantiate my fragments in this way in onCreate():
for(int x = 0; x < 3; x++) {
Bundle b = new Bundle();
b.putString( "id" , x );
Fragment myFrag = Fragment.instantiate( myContext , Mm_FragmentPage.class.getName() );
myFrag.setArguments( b );
fragments.add(myFrag);
}
Then I set the adapter in the ViewPager:
mPagerAdapter = new PagerAdapter( super.getSupportFragmentManager() , fragments );
mPager.setAdapter( mPagerAdapter );
Then I use the adapter in the TitlePageIndicator
titleIndicator = (TitlePageIndicator) findViewById( R.id.titleFragments );
titleIndicator.setViewPager( mPager );
titleIndicator.setOnPageChangeListener( new myPageChangeListener() );
And, at the end, the class PagerAdapter:
public class PagerAdapter extends FragmentPagerAdapter
{
// fragments to instantiate in the viewpager
private List<Fragment> fragments;
// constructor
public PagerAdapter(FragmentManager fm, List<Fragment> fragments)
{
super(fm);
this.fragments = fragments;
}
// return access to fragment from position, required override
#Override
public Fragment getItem(int position)
{
return this.fragments.get(position);
}
// number of fragments in list, required override
#Override
public int getCount()
{
return this.fragments.size();
}
#Override
public CharSequence getPageTitle(int position)
{
return getResources().getStringArray( R.array.tab_header_name )[ position ];
}
}
OK, so first thing you need to set OnPageChangeListener on the ViewPager and implement method onPageSelected(int i) and call the adapter's notifyDataSetChanged(), like so:
mPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int i, float v, int i2) {
}
#Override
public void onPageSelected(int i) {
//Tell the adapter that the content was changed
mPager.getAdapter().notifyDataSetChanged();
}
#Override
public void onPageScrollStateChanged(int i) {
}
});
In order to keep the fragments updated, you need to extends FragmentStatePagerAdapter and not FragmentPagerAdapter like what you did. The difference is that with FragmentPagerAdapter the ViewPager will never re-create the fragments, while in FragmentStatePagerAdapter it will.
Then on getItem(..) make sure to return a new instance of the fragment with the new content by passing the content to its arguments via setArguments(). Then override also getItemPosition(..) to tell the adapter that the fragment is not found, and therefore it must re-create it.
public class MyPagerAdapter extends FragmentStatePagerAdapter {
//List to hold the fragments to be shown
//NOTE: It's a list of Fragment classes, not a list of Fragment instances!
private List<Class<? extends Fragment> fragments;
public MyPagerAdapter(FragmentManager fm) {
super(fm);
fragments.add(SomeFragment.class);
fragments.add(AnotherFragment.class);
fragments.add(MoreFragment.class);
}
#Override
public Fragment getItem(int i) {
try {
//Creates a new instance of the fragment
Fragment instance = fragments.get(i).newInstance();
//Put the new content by passing Bundle with new content
instance.setArguments(args);
return instance;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
#Override
public int getItemPosition(Object object) {
//NOTE: you might want to put better logic here
return POSITION_NONE;
}
#Override
public int getCount() {
return pages.size();
}
}
Every time you slide from one fragment to another, onPageSelected() will be fired calling notifyDataSetChanged() which will force the adapter to check also if the position of the fragment has changed. Since we return POSITION_NONE in getItemPosition(..), the adapter thinks that the position changed and will then call getItem(i). In getItem(i) we return a new instance (optionally, passing new arguments). Problem solved! :)
I just tested it by myself, created a small app that have a counter which increases everytime the user slides the page and it works!
This way you can drop the ViewPager.SimpleOnPageChangeListener.onPageSelected.
Learn more about ViewPager.
I am using ViewPager with views V1, V2, V3 ..... I am trying to set visibility of a LinearLayout used in each view, by clicking on a button. Through this code it apply the change on the next view instead of the current view. e.g. I am on V5. When I click it hides/show the object on V6. If I am going backwards from V6 to V5, then it applies the change on V4.
Here is the code:
public class FragmentStatePagerSupport extends FragmentActivity {
static final int NUM_ITEMS = 10;
MyAdapter mAdapter;
ViewPager mPager;
static int mNum;
private Button btn_zoom;
static LinearLayout LL_Head;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_pager);
mAdapter = new MyAdapter(getSupportFragmentManager());
mPager = (ViewPager)findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
mPager.setCurrentItem(5);
btn_zoom = (Button)findViewById(R.id.btn_zoom);
btn_zoom.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
if (LL_Head.getVisibility() == View.VISIBLE) {
LL_Head.setVisibility(View.GONE);
}else{
LL_Head.setVisibility(View.VISIBLE);
}
}
});
.
.
.
}
public static class MyAdapter extends FragmentStatePagerAdapter {
public MyAdapter(FragmentManager fm) {
super(fm);
}
#Override
public int getCount() {
return NUM_ITEMS;
}
#Override
public Fragment getItem(int position) {
return ArrayListFragment.newInstance(position);
}
}
public static class ArrayListFragment extends ListFragment {
static ArrayListFragment newInstance(int num) {
ArrayListFragment f = new ArrayListFragment();
Bundle args = new Bundle();
args.putInt("num", num);
f.setArguments(args);
return f;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mNum = getArguments() != null ? getArguments().getInt("num") : 1;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.sura_vpager, container, false);
TextView tv1=(TextView) v.findViewById(R.id.txtHead);
tv1.setText("Fragment #" + mNum);
LL_Head = (LinearLayout)v.findViewById(R.id.LL_Head);
return v;
}
Please advise
Thanks
In order to make a fluent experience the ViewPager not only loads the view you are currently looking at, but also the adjacent views. That means, that if you are scrolling from position 0 to position 1, what actually happens is that position 2 is loaded, so it will be ready when you scroll on. This is why the change is applied to the "next" view, rather than the current one (if you scroll from view 2 to 1, then view 0 is created).
Since you are setting the static LinearLayout in OnCreate, then it's only the last view to be created that is changed - and this will only ever be the one you are looking at, if you have scrolled to the end of the pager. Instead you should keep track of which fragment the user is looking at (ViewPager.setOnPageChangeListener()) and cache the fragment in your adapter. You then know which fragment position you want, and when you ask for it, you will just return the one you previously created (don't create a new one, then it won't work :)).
Or, the tl;dr version:
LL_Head is almost always set to be the next fragment, not the current one. Don't set it statically. Cache it in your PagerAdapter and reget it when you need it.
Edit:
Alternatively you may want to have the fragments listen to an event of sorts, which tells them whether they should show or hide the layout in question. Otherwise it will only be the current fragment that is affected by this, rather than all fragments.
The numbering in Java starts from 0. Thus when you want to set the 5th item, you have to call mPager.setCurrentItem(4);
Hope this helps!