android - एक ViewPager से एक टुकड़ा पुनर्प्राप्त करें




android-fragments android-viewpager (15)

मैं तीन अलग-अलग टुकड़ों को होस्ट करने के लिए FragmentStatePagerAdapter साथ एक ViewPager का उपयोग कर रहा हूं:

  • [Fragment1]
  • [Fragment2]
  • [Fragment3]

जब मैं Fragment1 में ViewPager से Fragment1 प्राप्त करना चाहता हूं।

समस्या क्या है, और मैं इसे कैसे ठीक करूं?


ViewPager से वर्तमान दृश्य खंड प्राप्त करने के लिए। मैं इस सरल कथन का उपयोग कर रहा हूं और यह ठीक काम कर रहा है।

      public Fragment getFragmentFromViewpager()  
      {
         return ((Fragment) (mAdapter.instantiateItem(mViewPager, mViewPager.getCurrentItem())));
      }

/values/integers.xml में पूर्णांक संसाधन आईडी बनाएं

<integer name="page1">1</integer>
<integer name="page2">2</integer>
<integer name="page3">3</integer>

फिर पेजर एडाप्टर में इटिम फ़ंक्शन प्राप्त करें:

public Fragment getItem(int position) {

        Fragment fragment = null;

        if (position == 0) {
            fragment = FragmentOne.newInstance();
            mViewPager.setTag(R.integer.page1,fragment);

        }
        else if (position == 1) {

            fragment = FragmentTwo.newInstance();
            mViewPager.setTag(R.integer.page2,fragment);

        } else if (position == 2) {

            fragment = FragmentThree.newInstance();
            mViewPager.setTag(R.integer.page3,fragment);

        }

        return fragment;
        }

फिर गतिविधि में खंड को संदर्भित करने के लिए इस फ़ंक्शन को लिखें:

private Fragment getFragmentByPosition(int position) {
    Fragment fragment = null;

    switch (position) {
        case 0:
            fragment = (Fragment) mViewPager.getTag(R.integer.page1);
            break;

        case 1:

            fragment = (Fragment) mViewPager.getTag(R.integer.page2);
            break;

        case 2:
            fragment = (Fragment) mViewPager.getTag(R.integer.page3);
            break;
            }

            return fragment;
    }

उपर्युक्त फ़ंक्शन को कॉल करके खंड संदर्भ प्राप्त करें और फिर इसे अपने कस्टम खंड में डालें:

Fragment fragment = getFragmentByPosition(position);

        if (fragment != null) {
                    FragmentOne fragmentOne = (FragmentOne) fragment;
                    }

अपने FragmentPagerAdapter पर अगली विधियां जोड़ें:

public Fragment getActiveFragment(ViewPager container, int position) {
String name = makeFragmentName(container.getId(), position);
return  mFragmentManager.findFragmentByTag(name);
}

private static String makeFragmentName(int viewId, int index) {
    return "android:switcher:" + viewId + ":" + index;
}

getActiveFragment (0) को काम करना है।

ViewPager https://gist.github.com/jacek-marchwicki/d6320ba9a910c514424d में लागू समाधान यहां दिया गया है। अगर कुछ विफल हो जाता है तो आपको अच्छा क्रैश लॉग दिखाई देगा।


एक और आसान समाधान:

    public class MyPagerAdapter extends FragmentPagerAdapter {
        private Fragment mCurrentFragment;

        public Fragment getCurrentFragment() {
            return mCurrentFragment;
        }
//...    
        @Override
        public void setPrimaryItem(ViewGroup container, int position, Object object) {
            if (getCurrentFragment() != object) {
                mCurrentFragment = ((Fragment) object);
            }
            super.setPrimaryItem(container, position, object);
        }
    }

खंड प्रबंधक में टुकड़ों पर फिर से शुरू करने का आसान तरीका। व्यूपार्जर ढूंढें, जिसमें सेक्शन पोजिशन तर्क है, जो सार्वजनिक स्थैतिक प्लेसहोल्डर फ्रैगमेंट न्यू इंटेंसेंस (int sectionNumber) में रखा गया है।

public PlaceholderFragment getFragmentByPosition(Integer pos){
    for(Fragment f:getChildFragmentManager().getFragments()){
        if(f.getId()==R.id.viewpager && f.getArguments().getInt("SECTNUM") - 1 == pos) {
            return (PlaceholderFragment) f;
        }
    }
    return null;
}

टुकड़ा में

public int getArgument(){
   return mPage;
{
public void update(){

}

FragmentActivity में

List<Fragment> fragments = getSupportFragmentManager().getFragments();
for(Fragment f:fragments){
    if((f instanceof PageFragment)&&(!f.isDetached())){
          PageFragment pf = (PageFragment)f;   
          if(pf.getArgument()==pager.getCurrentItem())pf.update();
    }
}

मुझे ऐसा करने का एक आसान, साफ तरीका नहीं मिला। हालांकि, व्यूपेजर विजेट सिर्फ एक और व्यू ग्रुप है, जो आपके टुकड़े होस्ट करता है। ViewPager में इन टुकड़ों को तत्काल बच्चों के रूप में है। तो आप बस उन पर फिर से सक्रिय हो सकते हैं (.getChildCount () और .getChildAt ()) का उपयोग करके, और देखें कि क्या आप जिस खंड का उदाहरण खोज रहे हैं वह वर्तमान में ViewPager में लोड हो गया है और इसका संदर्भ प्राप्त हो सकता है। उदाहरण के लिए आप टुकड़ों को अलग करने के लिए कुछ स्थिर अद्वितीय आईडी फ़ील्ड का उपयोग कर सकते हैं।

ध्यान दें कि ViewPager ने उस टुकड़े को लोड नहीं किया हो जिसे आप खोज रहे हैं क्योंकि यह ListView जैसे वर्चुअलाइजिंग कंटेनर है।


मुझे पता है कि इसमें कुछ जवाब हैं, लेकिन शायद यह किसी की मदद करेगा। जब मैंने अपने ViewPager से Fragment प्राप्त करने की आवश्यकता होती है तो मैंने अपेक्षाकृत सरल समाधान का उपयोग किया है। ViewPager धारण करने वाली आपकी Activity या Fragment , आप इस कोड का उपयोग प्रत्येक Fragment माध्यम से चक्र में कर सकते हैं।

FragmentPagerAdapter fragmentPagerAdapter = (FragmentPagerAdapter) mViewPager.getAdapter();
for(int i = 0; i < fragmentPagerAdapter.getCount(); i++) {
    Fragment viewPagerFragment = fragmentPagerAdapter.getItem(i);
    if(viewPagerFragment != null) {
        // Do something with your Fragment
        // Check viewPagerFragment.isResumed() if you intend on interacting with any views.
    }
}
  • यदि आप ViewPager में अपने Fragment की स्थिति जानते हैं, तो आप केवल getItem(knownPosition) कॉल कर सकते हैं।

  • यदि आप ViewPager में अपने Fragment की स्थिति नहीं जानते हैं, तो आप अपने बच्चों के Fragments प्राप्त कर सकते हैं जैसे एक तरीका इंटरफ़ेस को getUniqueId() , और इसका उपयोग करने के लिए इसका उपयोग करें। या आप सभी Fragments माध्यम से चक्र कर सकते हैं और कक्षा के प्रकार की जांच कर सकते हैं, जैसे कि if(viewPagerFragment instanceof FragmentClassYouWant)

!!! संपादित करें !!!

मैंने पाया है कि getItem केवल एक FragmentPagerAdapter द्वारा कॉल किया जाता है जब प्रत्येक Fragment को पहली बार बनाया जाना चाहिए, उसके बाद, ऐसा लगता है कि Fragments का उपयोग करके Fragments का पुनर्नवीनीकरण किया जाता है। इस तरह, FragmentPagerAdapter कई कार्यान्वयन getItem में नए Fragment getItem । मेरी उपर्युक्त विधि का उपयोग करके, इसका मतलब है कि हम हर बार नए Fragment getItem को कॉल किया जाता है क्योंकि हम FragmentPagerAdapter में सभी आइटमों के माध्यम से जाते हैं। इसके कारण, मुझे FragmentManager का उपयोग करके प्रत्येक Fragment को प्राप्त करने के लिए एक बेहतर दृष्टिकोण मिला है (स्वीकृत उत्तर का उपयोग करके)। यह एक और पूरा समाधान है, और मेरे लिए अच्छा काम कर रहा है।

FragmentPagerAdapter fragmentPagerAdapter = (FragmentPagerAdapter) mViewPager.getAdapter();
for(int i = 0; i < fragmentPagerAdapter.getCount(); i++) {
    String name = makeFragmentName(mViewPager.getId(), i);
    Fragment viewPagerFragment = getChildFragmentManager().findFragmentByTag(name);
    // OR Fragment viewPagerFragment = getFragmentManager().findFragmentByTag(name);
    if(viewPagerFragment != null) {

        // Do something with your Fragment
        if (viewPagerFragment.isResumed()) {
            // Interact with any views/data that must be alive
        }
        else {
            // Flag something for update later, when this viewPagerFragment
            // returns to onResume
        }
    }
}

और आपको इस विधि की आवश्यकता होगी।

private static String makeFragmentName(int viewId, int position) {
    return "android:switcher:" + viewId + ":" + position;
}

मैंने इसे सभी टुकड़ों ( List<Fragment> fragments; ) की सूची बनाने से पहले संभाला था जिसे मैं उपयोग करने जा रहा था, फिर उन्हें पेजर में जोड़ा गया जिससे वर्तमान में देखे गए खंड को संभालना आसान हो गया।

इसलिए:

@Override
onCreate(){
    //initialise the list of fragments
    fragments = new Vector<Fragment>();

    //fill up the list with out fragments
    fragments.add(Fragment.instantiate(this, MainFragment.class.getName()));
    fragments.add(Fragment.instantiate(this, MenuFragment.class.getName()));
    fragments.add(Fragment.instantiate(this, StoresFragment.class.getName()));
    fragments.add(Fragment.instantiate(this, AboutFragment.class.getName()));
    fragments.add(Fragment.instantiate(this, ContactFragment.class.getName()));


    //Set up the pager
    pager = (ViewPager)findViewById(R.id.pager);
    pager.setAdapter(new MyFragmentPagerAdapter(getSupportFragmentManager(), fragments));
    pager.setOffscreenPageLimit(4);
}

तो फिर इसे कहा जा सकता है:

public Fragment getFragment(ViewPager pager){   
    Fragment theFragment = fragments.get(pager.getCurrentItem());
    return theFragment;
}

तो फिर मैं इसे एक कथन में चक कर सकता था जो केवल तभी चलाएगा जब यह सही टुकड़े पर था

Fragment tempFragment = getFragment();
if(tempFragment == MyFragmentNo2.class){
    MyFragmentNo2 theFrag = (MyFragmentNo2) tempFragment;
    //then you can do whatever with the fragment
    theFrag.costomFunction();
}

लेकिन यह सिर्फ मेरे हैक और स्लैश दृष्टिकोण है, लेकिन यह मेरे लिए काम करता है, मैं इसका उपयोग करता हूं जब बैक बटन दबाया जाता है तो मैं वर्तमान में प्रदर्शित खंड में परिवर्तन जारी करता हूं।


मैंने थोड़ा अलग दृष्टिकोण के साथ इसे आसान बना दिया।

मेरा कस्टम FragmentAdapter.getItem विधि नया MyFragment () नहीं लौटा, लेकिन FragmentAdapter कन्स्ट्रक्टर में बनाया गया MyFragment का उदाहरण।

मेरी गतिविधि में मुझे एडाप्टर से टुकड़ा मिला, जांचें कि यह उदाहरण है या नहीं, फ्रेगमेंट की आवश्यकता है, फिर आवश्यक विधियों को कास्ट करें और उपयोग करें।


यह उपरोक्त स्टीवन के उत्तर पर आधारित है। यह खंड के वास्तविक उदाहरण को वापस कर देगा जो पहले से ही मूल गतिविधि से जुड़ा हुआ है।

FragmentPagerAdapter fragmentPagerAdapter = (FragmentPagerAdapter) mViewPager.getAdapter();
    for(int i = 0; i < fragmentPagerAdapter.getCount(); i++) {

        Fragment viewPagerFragment = (Fragment) mViewPager.getAdapter().instantiateItem(mViewPager, i);
        if(viewPagerFragment != null && viewPagerFragment.isAdded()) {

            if (viewPagerFragment instanceof FragmentOne){
                FragmentOne oneFragment = (FragmentOne) viewPagerFragment;
                if (oneFragment != null){
                    oneFragment.update(); // your custom method
                }
            } else if (viewPagerFragment instanceof FragmentTwo){
                FragmentTwo twoFragment = (FragmentTwo) viewPagerFragment;

                if (twoFragment != null){
                    twoFragment.update(); // your custom method
                }
            }
        }
    }

व्यूपेजर से टुकड़ों को पकड़ने के लिए यहां और अन्य संबंधित एसओ धागे / ब्लॉगों पर बहुत सारे उत्तर हैं। मैंने जो भी देखा है, वह टूटा हुआ है, और वे आमतौर पर नीचे सूचीबद्ध दो प्रकारों में से एक में आते हैं। कुछ अन्य वैध समाधान हैं यदि आप केवल this खंड पर इस अन्य उत्तर की तरह वर्तमान खंड को पकड़ना चाहते हैं।

यदि FragmentPagerAdapter का उपयोग नीचे देखें। यदि FragmentStatePagerAdapter का उपयोग करके इसे देखने लायक है। फ्रैगमेंटस्टेट एडाप्टर में मौजूदा नहीं हैं जो ग्रैबिंग इंडेक्स उतना उपयोगी नहीं है जितना इसकी प्रकृति से इन्हें पूरी तरह से फेंक दिया जाएगा ऑफस्क्रीन सीमाओं के बाहर / बाहर से बाहर चला गया।

अपरिपक्व पाथ

गलत: टुकड़ों की अपनी आंतरिक सूची बनाए रखें, जब FragmentPagerAdapter.getItem() को कॉल किया जाता है

  • आमतौर पर SparseArray या Map का उपयोग करते हैं
  • मैंने देखा है कि कई उदाहरणों में से एक जीवन चक्र घटनाओं के लिए खाते हैं इसलिए यह समाधान नाजुक है। जैसा कि getItem को पहली बार केवल पृष्ठ कहा जाता है (यदि आपके ViewPager.setOffscreenPageLimit(x) > 0) को ViewPager में स्क्रॉल किया गया है (या प्राप्त हो रहा है, यदि होस्टिंग Activity / Fragment मारे गए या पुनरारंभ हो तो आंतरिक SpaseArray को मिटा दिया जाएगा कस्टम FragmentPagerActivity को फिर से बनाया गया है, लेकिन दृश्यों के पीछे ViewPagers आंतरिक टुकड़े पुनर्निर्मित getItem जाएंगे, और getItem किसी भी अनुक्रमणिका के लिए getItem नहीं कहा जाएगा, इसलिए सूचकांक से एक टुकड़ा प्राप्त करने की क्षमता हमेशा के लिए खो जाएगी। आप FragmentManager.getFragment() और putFragment माध्यम से इन खंड संदर्भों को सहेजकर और पुनर्स्थापित करके इसके लिए खाता बना सकते हैं लेकिन यह गन्दा IMHO प्राप्त करना शुरू कर देता है।

गलत: FragmentPagerAdapter में हुड के नीचे उपयोग की जाने वाली अपनी खुद की टैग आईडी का निर्माण करें और पृष्ठ को पुनर्प्राप्त करने के लिए इसका उपयोग करें FragmentManager से FragmentManager

  • यह बेहतर है क्योंकि यह पहले आंतरिक-सरणी समाधान में खोने वाले खंड-संदर्भ की समस्या का सामना करता है, लेकिन जैसा कि उपरोक्त उत्तरों और नेट पर कहीं और उत्तर में बताया गया है - यह हैकी को लगता है कि यह एक निजी विधि है जिसे ViewPager आंतरिक है किसी भी समय या किसी भी ओएस संस्करण के लिए बदल सकता है।

इस समाधान के लिए बनाई गई विधि है

private static String makeFragmentName(int viewId, long id) {
    return "android:switcher:" + viewId + ":" + id;
}

एक हैप्पी पाथ: ViewPager.instantiateItem()

उपरोक्त getItem() को getItem() करने के लिए एक समान दृष्टिकोण लेकिन गैर-जीवन चक्र-तोड़ना यह है कि इसे getItem() बजाय instantiateItem() में हुक करना instantiateItem() क्योंकि पूर्व में प्रत्येक बार इंडेक्स बनाया / एक्सेस किया जाएगा। यह जवाब देखें

एक हैप्पी पाथ: अपना खुद का FragmentViewPager निर्माण करें

नवीनतम समर्थन lib के स्रोत से अपनी खुद की FragmentViewPager कक्षा का निर्माण करें और खंड टैग उत्पन्न करने के लिए आंतरिक रूप से उपयोग की गई विधि को बदलें। आप इसे नीचे से बदल सकते हैं। इसका लाभ यह है कि आप जानते हैं कि टैग सृजन कभी नहीं बदलेगा और आप एक निजी एपीआई / विधि पर निर्भर नहीं हैं, जो हमेशा खतरनाक होता है।

/**
 * @param containerViewId the ViewPager this adapter is being supplied to
 * @param id pass in getItemId(position) as this is whats used internally in this class
 * @return the tag used for this pages fragment
 */
public static String makeFragmentName(int containerViewId, long id) {
    return "android:switcher:" + containerViewId + ":" + id;
}

फिर जब दस्तावेज़ कहता है, जब आप किसी इंडेक्स के लिए इस्तेमाल किए गए टुकड़े को पकड़ना चाहते हैं तो बस इस विधि की तरह कुछ कॉल करें (जिसे आप कस्टम FragmentPagerAdapter या subclass में डाल सकते हैं) यह जानकर कि नतीजा हो सकता है अगर परिणाम अभी तक नहीं कहा गया है उस पृष्ठ के लिए यानी इसे अभी तक नहीं बनाया गया है।

/**
 * @return may return null if the fragment has not been instantiated yet for that position - this depends on if the fragment has been viewed
 * yet OR is a sibling covered by {@link android.support.v4.view.ViewPager#setOffscreenPageLimit(int)}. Can use this to call methods on
 * the current positions fragment.
 */
public @Nullable Fragment getFragmentForPosition(int position)
{
    String tag = makeFragmentName(mViewPager.getId(), getItemId(position));
    Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag);
    return fragment;
}

यह एक साधारण समाधान है और वेब पर हर जगह पाए गए अन्य दो समाधानों में मुद्दों को हल करता है


सबसे आसान और सबसे संक्षिप्त तरीका। यदि ViewPager में आपके सभी टुकड़े अलग-अलग वर्गों के हैं, तो आप उन्हें निम्नानुसार प्राप्त कर सकते हैं और उन्हें अलग कर सकते हैं:

public class MyActivity extends Activity
{

    @Override
    public void onAttachFragment(Fragment fragment) {
        super.onAttachFragment(fragment);
        if (fragment.getClass() == MyFragment.class) {
            mMyFragment = (MyFragment) fragment;
        }
    }

}

FragmentPagerAdapter को अपने ViewPager एडाप्टर क्लास में विस्तारित करना होगा।
यदि आप FragmentStatePagerAdapter उपयोग करते हैं तो आप अपनी ID द्वारा अपनी Fragment नहीं ढूंढ पाएंगे

public static String makeFragmentName(int viewPagerId, int index) {
  return "android:switcher:" + viewPagerId + ":" + index;
}

इस विधि का उपयोग कैसे करें: -

Fragment mFragment = ((FragmentActivity) getContext()).getSupportFragmentManager().findFragmentByTag(
       AppMethodUtils.makeFragmentName(mViewPager.getId(), i)
);
InterestViewFragment newFragment = (InterestViewFragment) mFragment;

Fragment yourFragment = yourviewpageradapter.getItem(int index);

index एडाप्टर में टुकड़े की जगह है जैसे आपने fragment1 1 जोड़ा fragment1 तो पहले रेट्रेव fragment1 पास index 0 के रूप में और बाकी के लिए





android-viewpager