Is it possible to access the current Fragment bein

2019-01-10 14:29发布

问题:

I have an app with a ViewPager and three Fragments. I'm trying to figure out how to get the current Fragment being viewed so I can get at its arguments.

I have an OnPageChangeListener grabbing the current page index, but

ViewPager.getChildAt(int position);

returns a View. What's the relationship between this View and the current Fragment?

回答1:

I finally found an answer that worked for me. Basically, you can access the fragment for a viewPager page by using the tag "android:switcher:"+R.id.viewpager+":0".



回答2:

I've solved this problem the other way round. Instead of searching for the fragment from the activity, I'm registering the Fragment during it's onAttach() method at it's owner activity and de-registering it in the onStop() method. Basic Idea:

Fragment:

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    try{
        mActivity = (IMyActivity)activity;
    }catch(ClassCastException e){
        throw new ClassCastException(activity.toString() +" must be a IMyActivity");
    }

    mActivity.addFragment(this);
}

@Override
public void onStop() {
    mActivity.removeFragment(this);
    super.onStop();
}

IMyActivity:

public interface IFriendActivity {
    public void addFragment(Fragment f);
    public void removeFragment(Fragment f); 
}

MyActivity:

public class MyActivity implements IMyActivity{

    [...]

    @Override
    public void addFragment(Fragment f) {
        mFragments.add(f);
    }

    @Override
    public void removeFragment(Fragment f) {
        mFragments.remove(f);
    }

}


回答3:

Edit - Don't do this. If you're tempted to, read the comments for why it's a bad idea.

On the odd-chance you're still trying to solve this problem:

Extend FragmentPagerAdapter. In the constructor, build the Fragments you need and store them in a List (array/ArrayList) of Fragments.

private final int numItems = 3;
Fragment[] frags;

public SwipeAdapter (FragmentManager fm) {
    super(fm);

    //Instantiate the Fragments
    frags = new Fragment[numItems];

    Bundle args = new Bundle();
    args.putString("arg1", "foo");

    frags[0] = new MyFragment();
    frags[1] = new YourFragment();
    frags[2] = new OurFragment();
    frags[2].setArguments(args);
}

Then for getItem(int position), you can do something like

public Fragment getItem(int position) {
    return frags[position];
}

I'm not sure if this is the generally accepted way of doing it but it worked for me.

Edit

This is really not a good way to go. If you plan on handling orientation changes or your app going into the background, then this will probably break your code. Please read the comments below this answer for more info. Rather use @James 's answer



回答4:

Yes, it's possible if you are using FragmentStatePagerAdapter.

ViewPager vp;
//...
YourFragment fragment = (YourFragment) adapter.instantiateItem(vp, vp.getCurrentItem());


回答5:

PLEASE DON'T USE THIS

Make your adapter extend the following FragmentStatePagerWithCurrentAdapter class and instead of implementing getItem implement the same code into getItemAtIndex

Set the ViewPager OnPageChangeListener, to the instance of the adapter.

When you need to access the current Fragment you just call adapter.getCurrentItem().

package your.package;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.SparseArray;
import android.view.ViewGroup;

public abstract class FragmentStatePagerWithCurrentAdapter 
extends FragmentStatePagerAdapter 
implements OnPageChangeListener {
    int currentPage = 0;

    private SparseArray<Fragment> mPageReferenceMap = new SparseArray<Fragment>();

    public FragmentStatePagerWithCurrentAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public final Fragment getItem(int index) {
        Fragment myFragment = getItemAtIndex(index);
        mPageReferenceMap.put(index, myFragment);
        return myFragment;
    }

    public abstract Fragment getItemAtIndex(int index);

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {

        super.destroyItem(container, position, object);

        mPageReferenceMap.remove(Integer.valueOf(position));
    }

    public Fragment getCurrentItem() {
        return mPageReferenceMap.get(currentPage);
    }

    @Override
    public void onPageScrollStateChanged(int arg0) {

    }

    @Override
    public void onPageScrolled(int arg0, float arg1, int arg2) {

    }

    @Override
    public void onPageSelected(int newPageIndex) {
        currentPage = newPageIndex;
    }

}

I used as reference the following blog post: http://tamsler.blogspot.com/2011/11/android-viewpager-and-fragments-part-ii.html



回答6:

It's been explained here : http://developer.android.com/guide/topics/fundamentals/fragments.html

In OnCreateView you must return a view to draw a UI for your fragment, I think that's the relationship.

Also this question might be similar: Get focused View from ViewPager



回答7:

You can do so: - On the class extent of a view pager adapter (such as PagerAdapter , FragmentStatePagerAdapter...) override method instantiateItem :

@Override
public Object instantiateItem(ViewGroup container, int position) {
        final Fragment frag = (Fragment) super.instantiateItem(container, position);
        if(frag instanceof ListNoteOfTypeFragment){                
            final ListNoteOfTypeFragment listNoteOfTypeFragment = (ListNoteOfTypeFragment) frag;
            //do whatever you want with your fragment here
            listNoteOfTypeFragment.setNoteChangeListener(mListener);
        }
        return frag;
    }    


回答8:

Definitive answer that works seamlessly (but small hack):

somewhere in page fragment's layout:

<FrameLayout android:layout_width="0dp" android:layout_height="0dp" android:visibility="gone" android:id="@+id/fragment_reference">
     <View android:layout_width="0dp" android:layout_height="0dp" android:visibility="gone"/>
</FrameLayout>

in fragment's onCreateView():

...
View root = inflater.inflate(R.layout.fragment_page, container, false);
ViewGroup ref = (ViewGroup)root.findViewById(R.id.fragment_reference);
ref.setTag(this);
ref.getChildAt(0).setTag("fragment:" + pageIndex);
return root;

and method to return Fragment from ViewPager, if exists:

public Fragment getFragment(int pageIndex) {        
        View w = mViewPager.findViewWithTag("fragment:" + pageIndex);
        if (w == null) return null;
        View r = (View) w.getParent();
        return (Fragment) r.getTag();
}


回答9:

Jorge Garcia's FragmentStatePagerWithCurrentAdapter is a very good solution but it needs a minor improvement. In case the activity gets destroyed and re-created in response to a configuration change or something like that the getItem will not be called for the fragments that were saved and retrieved by the fragment manager. So I override getItem normally in my subclass and I put the following in the FragmentStatePagerWithCurrentAdapter

@Override
public Object instantiateItem(ViewGroup container, int position) {
    Object item = super.instantiateItem(container, position);
    if ( item instanceof Fragment ) {
        pageReferenceMap.put(position, (Fragment)item);
    }
    return item;
}

The instantiateItem is called every time the fragment in that position is accessed.



回答10:

Or just save all Fragments in a map:

public class MyFragment extends Fragment implements OnPageChangeListener {

    private ViewPager viewPager;
    private FragmentStatePagerAdapter viewAdapter;
    private View rootView;
    private Map<Integer, Fragment> fragments = new HashMap<Integer, Fragment>();

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        rootView = inflater.inflate(R.layout.introdution, container, false);

        viewPager = (ViewPager) rootView.findViewById(R.id.pager);
        viewAdapter = new ViewAdapter(getFragmentManager());
        viewPager.setAdapter(viewAdapter);
        viewPager.addOnPageChangeListener(this);

        return rootView;

    }

    private class ViewAdapter extends FragmentStatePagerAdapter {

        public ViewAdapter(FragmentManager fragmentManager) {
            super(fragmentManager);
        }

        @Override
        public Fragment getItem(int position) {

            Fragment result = null;

            switch (position) {
                case 0: result = Fragment1.newInstance(); break;
                case 1: result = Fragment2.newInstance(); break;
            }

            if (result != null)
                fragments.put(position, result);

            return result;

        }

        @Override
        public int getCount() {

            return 2;
        }

    }

    @Override
    public void onPageScrollStateChanged(int arg0) {
    }

    @Override
    public void onPageScrolled(int arg0, float arg1, int arg2) {
    }

    @Override
    public void onPageSelected(int position) {

        Fragment currentFragment = fragments.get(position);

    }

}


回答11:

I think there is the better way by using this

Log.i(TAG, "getCurrentItem " + mViewPager.getCurrentItem());

Can get the current display fragment page.