Consider there is an activity with a title. Viewpager fragment is inside the activity. Fragment will be loaded with data from network API.
Now I need to update the activity title after getting the data from API.
Problem:
Since Viewpager is used, it loads the (prev), current, (next) fragments too. So activity is not aware of which title it is for.
Each title is different for each fragment, so I need to update the title only when the user views that fragment.
You need to create object of your Activity, By using this Object you are able to use activity method.
For more detail; visit this link.How to use method from another Class?
Use this with addOnPageChangeListener method of pager, in it you will get your current postion of pager.
In you Activity add the listener on ViewPager:
viewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener()
{
#Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
{
}
#Override public void onPageSelected(int position)
{
//You can use switch case too
if (position== 0)
{
//set title
}
else if (position== 1)
{
//set title
}...
}
#Override public void onPageScrollStateChanged(int state)
{
}
});
You can call the Activity method from Fragment by
Make method in Activity public
In fragment use getActivty() -> cast it to corresponding Activity then call this method
If you want to call Activity method only when fragment visible you can try https://stackoverflow.com/a/42019934/5381331
In Activity, you want to get the current visible fragment, you can try https://stackoverflow.com/a/47789367/5381331
Related
I have one fragment where are three (default) images and when user click on them, they will change to another. But when i swipe to another fragment and back to fragment with images there are not default ones as on the start. When I swipe two times so I will pass to another fragment (distance from original with images is 2 fragments) images are resetted to default. I was trying to implement setOffscreenPageLimit() from ViewPager and set it to 1, but minimum "length" when views in fragments are resetted is 2. How can I change that images to default manually after swipe action? Thank you.
Edit: I think that issue why onResume() is not working here: Fragment onResume not called
but i dont know what that means :/ I have three classes FragmentController.class, PagerAdapter.class and class of specific fragment for example FirstFragment.class. I don't know how connect these classes together.
Check that you create the fragments in the getItem() method of the adapter and do not hold any reference to that fragments (only WeakReferences if necessary), otherwise the fragments could not be destroyed.
EDIT:
The first fragment is unloaded only when you are in the third one because setOffscreenPageLimit is at least 1 so a viewpager allways loads the fragments that are at both sides of the selected one.
What you could do is to update your adapter with this code to provide a getFragment(position) method:
private HashMap<Integer, WeakReference<Fragment>> fragmentReferences = new HashMap<>();
#Override
public Fragment getItem(int position) {
Fragment fragment;
switch (position) {
case 0:
fragment = FirstFragment.newInstance();
break;
// etc
}
fragmentReferences.put(position, new WeakReference<>(fragment));
return fragment;
}
public Fragment getFragment(int position) {
WeakReference<Fragment> ref = fragmentReferences.get(position);
return ref == null ? null : ref.get();
}
After then you can get the selected fragment and call the method you want from the first fragment when a page is selected:
viewPager.setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageSelected(int currentPage) {
if (currentPage == 0) {
Fragment firstFragment = adapter.getFragment(0);
if (firstFragment != null) {
// This method resets the images of the first fragment
((FirstFragment) firstFragment).reset();
}
}
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// Do nothing
}
#Override
public void onPageScrollStateChanged(int state) {
// Do nothing
}
});
Well, I think the title is quite self explanatory. I have a ViewPager in my HomeActivity, the ViewPager contains 5 fragments at the moment.
When one of the fragments is visible by calling ViewPager's onPageScrolled I want to modify some views inside the current displayed fragment according to some conditions in the HomeActiviy.
After some research, it seems like I cannot find a good way to communicate in the direction HomeActivity --> Fragments inside ViewPager.
I have easily solved the communication in the direction Fragments in ViewPager --> HomeActivity using an Interfacebut this trick seems to not be working on the other direction.
I can access each time the current displayed fragment using a method on my FragmentStatePagerAdapter
public Fragment getActiveFragment(int position){
return myFragmentsList.get(position);
}
However, by doing that, I would have to cast each Fragment into its class MyFragment1 MyFragment2 MyFragment3....
Any easy clean way to achieve that?. Here is the relevant portion of the code:
mPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (currentStatus == 1){
Fragment activeFrag = mPagerAdapter.getActiveFragment(mPager.getCurrentItem());
//here I would like to modify one of the 5 fragments
}
#Override
public void onPageSelected(int position) {}
#Override
public void onPageScrollStateChanged(int state) {}
});
Define an interface,
interface FragmentListenerInterface {
public void onFragmentSelected();
}
Implement this interface in all of your fragments. change the communication between fragment and viewpager. write a method to return fragmentlistenerinterface instead of fragment.
public FragmentListenerInterface getActiveFragment(int position){
return (FragmentListenerInterface) myFragmentsList.get(position);
}
After this just say, in your code
public void onPageSelected(int position) {
mViewPager.getActiveFragment(position).onFragmentSelected();
}
And implement onFragmentSelected() in every fragment.
I have Nested Fragments [1 main Fragment called "MainFrag" and many child Fragments]
the App can show MainFrag or can show other fragments.
what I want to do is to setCurrentItem of MainFrag's ViewPager every time the user selects to show that MainFrag so I tried to put it at it's onCreateView but this only works for the first time the User Shows MainFrag as if user Selects another fragment and then re-selects MainFrag the seCurrentItem is not working
I also tried to put it inside MainFrag's onResume, It worked as required but it also causes a problem that if the user moved the App to background and then reOpen it viewPager will Scroll and i don't want this
So where Exactly Can I put setCurrentItem ?
mViewPager.setCurrentItem(mCurrentWeekFragmentItemNumber);
Edit: I am using Navigation Menu to Move between 3 main fragments where MainFrag is one of them.
After your mViewPager.setAdapter(adapter); method you can put
mViewPager.setCurrentItem(mCurrentWeekFragmentItemNumber);
After setting adapter to viewpager add setCurrentItem method
mViewPager.setAdapter(adapter);
mViewPager.setCurrentItem(mCurrentWeekFragmentItemNumber);
Try this:
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
viewPager.setCurrentItem(position);
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
}
I have a ViewPager with 10 pages. When I start the last (10th) page onCreateView() method of my fragment is called. When I swipe to the 9th page onCreateView() is called also. But when I back to the 10th page onCreateView() isn't called. What's wrong?
Try Extending FragmentStatePagerAdapter
That is because a FragmentPagerAdapter keeps in memory every fragment. Hence, when you visit the first time the fragment, onCreate will be invoked but the second time Android will looking for in memory, so it not need invoke onCreate.
If you need run the code in OnCreate every time fragment is displayed, you should move it to getItem(int id)
See offical documentation: http://developer.android.com/reference/android/support/v4/app/FragmentPagerAdapter.html
Nothing is wrong. The ViewPager already has the page, and so it does not need to create it.
I had the same problem, my solution was to assign again the adapter of the ViewPager instance, just like:
pager.setAdapter(adapter);
This causes a restart of the "mItems" property from the viewPager and removes the cache.
But I don't know if it's a safe solution
You can call the adapter getItem from onPageSelect, which is called also on swipes, and place your code inside the getItem, or even in the onPageSeelect itself.
CommonWare's answer is the best and works like charm:
simple add OnPageChangeListener to your ViewPager item, something like this:
ViewPager viewPager = null;
PagerAdapter pagerAdapter = null;
//Some code come here...
pagerAdapter = new PagerAdapter(); //Or any class derived from it
viewPager = (ViewPager)findViewById(R.id.container);//Connect it to XML
viewPager.setAdapter (mPagerAdapter); //Connect the two
//Next two lines are simply for fun...
//viewager.setPageTransformer(true, new DepthPageTransformer());
//viewPager.setPageTransformer(true, new PaymentZoomOutPageTransformer());
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
//This is the right place to connect the pages with a data struct!!!
#Override
public void onPageSelected(int position) {
// Here you can connect the current displayed page with some data..
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
//Here use the inflater to add views/pages
//Don't forget to do:
pagerAdapter.notifyDataSetChanged();
//When you're done...
Good day all, i have a slight issue i can't seem to get my head around it. i have a ViewPager of 3 fragments and this ViewPager is contained in a FrameLayout. What i am trying to do is that for every fragment, the background image of the FrameLayout Changes.
my FragmentActivity is:
pagerAdapter = new MyPagerAdapter(getSupportFragmentManager(), fragments);
pager = (ViewPager)findViewById(R.id.viewpager);
pager.setAdapter(pagerAdapter);
and in my MyPagerAdapter, i instantiate the fragments in the getItem() method:
#Override
public Fragment getItem(int position) {
return MyFragment.newInstance(position);
}
Now i can setup the values for the Views in the fragment correctly using the position
public static MyFragment newInstance(int position){ //Add arraylist of hashmaps to populate it here.
MyFragment my_fragment = new MyFragment();
Bundle bundle = my_fragment.getArguments();
if(bundle == null){
bundle = new Bundle();
}
bundle.putInt(FRAGMENT_POSITION, position);
my_fragment.setArguments(bundle);
return my_fragment;
}
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
Bundle args = getArguments();
if(args != null){
position = args.getInt(FRAGMENT_POSITION);
}
//do other operations and Methods on views based on position.
and then at somepoint, i call a method `((MyFragmentActivity)getActivity()).setLayoutBackground(resId) which sets the Background of the FrameLayout in the container Activity. My trouble is that, i can't seem to differentiate which fragment is being called due to the nature that ViewPagers Load all the fragments together and I keep getting the same background for all the fragments in the ViewPager.
In MyFragmentActivity, i tried changing it in the PageChangeListener but no luck, i noticed that i am passing the same value all the time and so keep getting the same thing.
public void setLayoutBackground(int resId){
layoutResId = resId;
pager.setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageSelected(int pos) {
app.setBackground(layout, layoutResId)
//Log.d(TAG, "i am resId" + layoutResId);
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
// TODO Auto-generated method stub
}
#Override
public void onPageScrollStateChanged(int arg0) {
// TODO Auto-generated method stub
}
});
}
What i need to do is pass the Position of the Fragment to the FragmentActivity so that it will load the correct Background but can't seem to figure it out. (The background drawable to load is based on a logic, so i can't define it from the start)Any Ideas how i could go about this or what i could be doing wrong because it has dealt with my weekend so far.. :) Many Thanks in Advance.
Instead of letting the Fragment set the layout background directly, have an HashMap<Integer, Integer> fragmentBackgrounds; field variable in the Activity and replace the method call to ((MyFragmentActivity)getActivity()).setLayoutBackground(resId) with ((MyFragmentActivity)getActivity()).setFragmentBackground(position, resId) where the Activity then puts the resId into the fragmentBackgrounds map with a key representing the position and the value representing the resId. In the onPageSelected() method of the PageChangeListener, use the position it gives you to look up the resource in your map that that Fragment would like and set the layout background at that time (unless the key doesn't exist or the value is null or 0 of course).
You should also consider not calling the setFragmentBackground in the way that you are, because that assumes that the hosting Activity will always be an instance of MyFragmentActivity and instead you should define an interface with the setFragmentBackground method and make the Activity implement that interface. Then, in the Fragment, override onAttach, check that the Activity that the Fragment is being attached to implements the interface with instanceof and assign the Activity to a field variable in the Fragment called listener. In onDetach() set the listener to null and always check if the listener is null before calling any methods on it.