Bir ViewPager'den Parça Alma


248

Üç farklı parçayı barındırmak için bir ile ViewPagerbirlikte kullanıyorum FragmentStatePagerAdapter:

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

Almak istediğim zaman Fragment1gelen ViewPageriçinde FragmentActivity.

Sorun nedir ve nasıl düzeltebilirim?

Yanıtlar:


504

Ana cevap, çerçeve tarafından oluşturulan bir isme dayanır. Bu hiç değişmezse, artık çalışmaz.

Ağır basan bu çözümün ne olacak, instantiateItem()ve destroyItem()senin gerçek web Fragment(State)PagerAdapter:

public class MyPagerAdapter extends FragmentStatePagerAdapter {
    SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();

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

    @Override
    public int getCount() {
        return ...;
    }

    @Override
    public Fragment getItem(int position) {
        return MyFragment.newInstance(...); 
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Fragment fragment = (Fragment) super.instantiateItem(container, position);
        registeredFragments.put(position, fragment);
        return fragment;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        registeredFragments.remove(position);
        super.destroyItem(container, position, object);
    }

    public Fragment getRegisteredFragment(int position) {
        return registeredFragments.get(position);
    }
}

Mevcut Fragmanlarla uğraşırken bu benim için işe yarıyor gibi görünüyor. Henüz somutlaştırılmamış olan parçalar arama sırasında null değerini döndürür getRegisteredFragment. Ama bunu çoğunlukla akımdan Fragmentçıkarmak için kullanıyorum ViewPager: adapater.getRegisteredFragment(viewPager.getCurrentItem())ve bu geri dönmeyecek null.

Bu çözümün başka dezavantajlarının farkında değilim. Eğer varsa, bilmek isterim.


41
Bu benim de düşünebileceğim en iyi çözüm. Sadece öneri belki yok edilen bir parçanın çöp toplanmasını engellemediğinizi garanti etmek için Fragmentiçine sarmak olabilir WeakReferencemi? Yapılacak doğru şey gibi görünüyor ...
Alex Lockwood

7
MyPagerAdapterYaşam döngüsü (yani döndürme) nedeniyle yok edildiğinde, registerdFragmentskaybolmayacaksa ne olur ? Will Activity/ Fragmentkullanarak MyPagerAdapterkaydetmek zorunda onSaveInstanceStateve sonra yeni ile güncellemeniz gerekir FragmentManagerref?
Steven Byle

10
Yanılmıyorsam (ve bunu kontrol etmelisiniz), getItem yöntemi - bildiğiniz gibi - çağrılmaz, ancak bir döndürmeden sonra çerçeve tarafından geri yüklenen her Parça için instantiateItem yöntemi çağrılır.
Boston Sokakları

6
Evet , çağrı cihazında tuttuğu durumları geri getItemyüklediğinden, döndürmede (önceden oluşturulmuş herhangi bir frags için) tekrar çağrılmadığını doğruladım . Eğer her çağrılan geri yüklenir, daha sonra bu çözüm aslında içindedir güvenli ve daha ileride ispat mayın veya kabul cevap daha. Bunu kendim denemeyi düşüneceğim. FragmentManagerFragmentsinstantiateItemFragment
Steven Byle

6
@Dori Kırmam. Benim çözümüm 'getItem ()' çağrısının sonucunu kullanmıyor. Bunun yerine, 'instantiateItem ()' çağrısından saklanan sonucu kullanıyor. Saklanan parça 'destroyItem ()' çağrısında seyrek diziden kaldırılacağından parçanın yaşam döngüsü bozuk değildir.
Boston Sokakları

85

Bir ViewPager'den parça kapmak için burada ve diğer ilgili SO iş parçacıklarında / bloglarında çok fazla cevap var. Gördüğüm herkes kırıldı ve genellikle aşağıda listelenen iki türden birine düşüyor gibi görünüyor. Sadece geçerli parçayı almak istiyorsanız, bu konudaki diğer cevap gibi başka geçerli çözümler de var .

Kullanıyorsanız, FragmentPagerAdapteraşağıya bakın. Kullanılıyorsa FragmentStatePagerAdapterdeğerini bakarak bu . Bir FragmentStateAdapter içinde geçerli olmayan kapma indeksleri, doğası gereği, bu tamamen yırtılacak kadar offScreenLimit sınırlarının dışına çıktı / çıktı gibi yararlı değildir.

MUTLU YOLLAR

Yanlış: Ne zaman FragmentPagerAdapter.getItem()çağrıldığına eklenen kendi dahili parça listenizi koruyun

  • Genellikle bir SparseArrayveyaMap
  • Gördüğüm pek çok örnekten biri yaşam döngüsü olaylarını açıklamıyor, bu yüzden bu çözüm kırılgandır. Gibi getItemsadece bir sayfa kaydırılan ilk kez olarak adlandırılır (veya eğer elde senin ViewPager.setOffscreenPageLimit(x)> 0) içinde ViewPagerbarındırma eğer Activity/ Fragmento öldürüldü veya yeniden iç SpaseArrayözel FragmentPagerActivity yeniden edildiğinde sildi, ama olacak perde arkasında ViewPagers iç fragmanları yeniden oluşturulur ve getItemolacak dEĞİL endeksler herhangi biri için çağrılabilir, böylece dizinden bir parçasını alma yeteneği sonsuza dek kaybolur. Bunu, bu parça referanslarını kaydederek ve geri yükleyerek hesaplayabilirsiniz FragmentManager.getFragment()ve putFragmentbu dağınık IMHO'yu almaya başlar.

Yanlış: Kaputun altında kullanılanla eşleşen kendi etiket kimliğinizi oluşturunFragmentPagerAdapter ve bunu Parçalar sayfasından almak için kullanın.FragmentManager

  • Bu, ilk dahili dizi çözümündeki kaybetme-parça-referans sorunu ile başa çıktığı için daha iyi, ancak yukarıdaki cevaplarda ve nette başka yerlerde doğru bir şekilde işaret edildiği gibi - bu, dahili bir özel yöntem ViewPagerolabilir. herhangi bir zamanda veya herhangi bir işletim sistemi sürümü için değiştirin.

Bu çözüm için yeniden oluşturulan yöntem

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

MUTLU BİR YOL: ViewPager.instantiateItem()

Benzer bir yaklaşım, getItem()üzerinde fakat olmayan yaşam döngüsü kırma bu kanca için olan instantiateItem()yerine getItem()önceki indeks / oluşturulur erişilen her çağrılır. Bu cevaba bakın

MUTLU BİR YOL: Kendinizi oluşturun FragmentViewPager

En son destek lib kaynağından kendi FragmentViewPagersınıfınızı oluşturun ve parça etiketlerini oluşturmak için dahili olarak kullanılan yöntemi değiştirin. Aşağıdakiler ile değiştirebilirsiniz. Bu, etiket oluşturma işleminin asla değişmeyeceğini ve her zaman tehlikeli olan özel bir api / yönteme güvenmemenizi bilmenin avantajına sahiptir.

/**
 * @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;
}

Daha sonra doc'ın dediği gibi, bir dizin için kullanılan bir parçayı almak istediğinizde, getItem henüz çağrılmadıysa FragmentPagerAdaptersonucun boş olabileceğinin farkında olarak bu yöntem (özel veya alt sınıfa koyabilirsiniz) gibi bir şey çağırmanız yeterlidir. o sayfa yani henüz oluşturulmadı.

/**
 * @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;
}

Bu basit bir çözümdür ve web'in her yerinde bulunan diğer iki çözümdeki sorunları çözer


6
Bu işe yarayacaktır, ancak ViewPager sınıfını kendi kaynak kodunuza kopyalamayı gerektirir. Bir ViewPager çağrı cihazı bağdaştırıcısının 'instantiateItem ()' ve 'destroyItem ()' işlevlerine güvenmek işe yarayacak ve parçaların yaşam döngülerini onurlandıracaktır (kaydedilen bir örnek durumundan parçalar oluşturulduğunda bu 2 yöntem de denir). Haklısınız, çağrılan 'getItem ()' yöntemine güvenmek iyi bir fikir değildir ve özel API'leri kullanmanın da bir yolu yoktur.
Boston Sokakları

+1, aynı zamanda bir çözüm olduğunu ve yukarıda düzenlediğini kabul ediyorum. Tek fark, yukarıdaki kullanımın instantiateItem(), bir yaşam döngüsü olayı gerçekleştikten sonra henüz ziyaret edilmemiş bir parçaya erişmek istediğiniz ve yaşam döngüsü olayından önce ziyaret edildiğiniz bir daha fazla kullanım durumunda çalışmasıdır. Bildiğim küçük bir fark ama benim programımda ince bir hataya neden olan şey, bu yüzden bana bunu bakıyor.
Dori

SetOffscreenPageLimit = 1 (varsayılan) ise, FragmentStatePageAdapter görünüm sayfalarına erişilirken bellek içinde ve dışında parçaları değiştirmeye başlar. GetItem () çağrısıyla, yeniden ziyaret edilen sayfaların / parçaların yeni bir örneği oluşturulur. Böyle bir yeniden ziyaret üzerine, sisteme yeni bir tane oluşturmak yerine, daha önce oluşturulmuş örnekleri devam ettirmesini bildirmenin bir yolu var mı?
carl

sayfa sınırının dışındaysa yeni bir tane oluşturmanız gerekir - ancak kaydedilen durumu geçirir. Eski olanları saklamak istiyorsanız sayfa sınırını artırabilirsiniz
Dori

@Dori hiçbir orada getItemId(pos)içerideFragmentStatePagerAdapter
Jemshit iskenderov

70

FragmentPagerAdapter'ınıza sonraki yöntemleri ekleyin:

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) çalışmak zorundadır.

ViewPager'e uygulanan çözüm https://gist.github.com/jacek-marchwicki/d6320ba9a910c514424d . Bir şey başarısız olursa iyi kilitlenme günlüğü görürsünüz.


Çok teşekkürler:) . Bu arada parçayı göndermek için bir işleyici kullandığım başka bir şekilde buldum. Bu çok uygun değil ama sonunda sorunu çözdü. Bu arada, çok
iyisin

12
Bu yöntemi kullanıyordum, ancak API 17'ye (?) Taşındığımda çalışmayı bıraktığına inanıyorum. Başka bir yöntem öneririm ve Google, konumu göz önüne alındığında bir ViewPager'den Parça almak için bir API yayınladıysa tercih ederdim.
gcl1

ikinci parça çağıran sorun var, yöntem yeni bir tane oluşturmak
Vasil Valchev

2
Bazı API sürümü makeFragmentName yöntemi özel statik olarak değiştirildi String makeFragmentName (int viewId, long id) {return "android: switcher:" + viewId + ":" + id; } bu nedenle getActiveFragment yöntemi şu şekilde görünmelidir (ikinci bağımsız değişken için konum yerine getItemId kullanın) public Fragment getActiveFragment (ViewPager container, int position) {String name = makeFragmentName (container.getId (), getItemId (position)); return mFragmentManager.findFragmentByTag (ad); }
Eugene Popovich

1
Gerçekten işe yarıyor ama gerçekten tehlikeli çünkü görünüm çağrı cihazının iç uygulamasına geçiyor ve google uygulamayı değiştirecekse (ve onlar yapabilir) kötü şeyler olacak. Umarım goole canlı parçayı almayı sağlar
shem

38

Başka bir basit çözüm:

    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);
        }
    }

1
Mevcut parça ihtiyaçlarım için mükemmel görünüyor.
danny117

Tek yapmanız gereken seçili Parçayı almaksa, ihtiyacınız olan tek şey budur - setPrimaryItem yöntemi ekte ve ayrıca geçerli öğe olarak Parçanın iç kümesinde güncellenen her birinde ayarlanır.
Graeme

1
Bu güzel bir çözüm gibi geliyor ama kullanamadıktan sonrasetPrimaryItem() denir :-( ViewPager.OnPageChangeListener#onPageSelected()
hardysim

21

Bunun birkaç cevabı olduğunu biliyorum, ama belki bu birine yardımcı olacaktır. Ben almak gerektiğinde ben nispeten basit bir çözüm kullandık Fragmentne biz den ViewPager. Sahip olduğunuzda Activityveya Fragmentelinde tuttuğunuzda, ViewPagerbu kodu, Fragmentsahip olduğu her şeyde dolaşmak için kullanabilirsiniz .

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.
    }
}
  • Aşağıdaki konularda konumunu biliyorsanız Fragmentiçinde ViewPager, sadece çağırabilir getItem(knownPosition).

  • Aşağıdaki konularda konumunu bilmiyorsanız Fragmentiçinde ViewPager, çocuklarınızın olabilir Fragmentsgibi bir yöntemle bir arabirim uygulamak getUniqueId()ve bunları ayırt etmek için bunu kullanın. Veya hepsini gözden geçirebilir Fragmentsve sınıf türünü kontrol edebilirsiniz.if(viewPagerFragment instanceof FragmentClassYouWant)

!!! DÜZENLE !!!

Ben getItemsadece FragmentPagerAdapterher biri ilk kezFragment oluşturulması gerektiğinde bir tarafından çağrıldığını keşfettim , bundan sonra, kullanarak geri dönüştürülmüş görünür . Bu şekilde, birçok uygulamaları oluşturmak yeni olduğundan da . Yukarıdaki yöntemimi kullanarak, her öğede yeni öğeleri oluşturacağımız anlamına gelir . Bu nedenle, bunun yerine her birini almak için (kabul edilen cevabı kullanarak) kullanarak daha iyi bir yaklaşım buldum . Bu daha eksiksiz bir çözüm ve benim için iyi çalışıyor.FragmentsFragmentManagerFragmentPagerAdapter FragmentgetItemFragmentgetItemFragmentPagerAdapterFragmentManagerFragment

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
        }
    }
}

Ve bu yönteme ihtiyacınız olacak.

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

1
SadeceFragmentByTag () öğesini bulursunuz, ancak ETİKET'i parça ile nereye ayarlayabiliriz ??
Mart'ta VinceStyling

@vince ViewPagerKendisi bu etiketleri ayarlar. Bu çözüm kırılgandır çünkü "gizli" adlandırma kuralını bilmeye dayanır ViewPager. Boston sokaklarının cevabı şimdi projemde kullandığım çok daha kapsamlı bir çözüm (bu yaklaşım yerine).
Steven Byle

Harika çalışıyor! Ancak ekran dışı ListFragment sayfaları güncellemem gerektiğinden "if (viewPagerFragment.isResumed ())" koşulunu kaldırdım. Ardından kullanıcı ListFragment sayfasına geri döndüğünde, tümü yeni verilerle güncellenir.
JDJ

10

Benim durumum için, yukarıdaki çözümlerin hiçbiri işe yaramadı.

Ancak, Çocuk Parçası Yöneticisi'ni bir Parçada kullandığım için, aşağıdakiler kullanıldı:

Fragment f = getChildFragmentManager().getFragments().get(viewPager.getCurrentItem());

Bu, yalnızca Yönetici'deki parçalarınızın viewpager öğesine karşılık gelmesi durumunda çalışır.


Bu, aktivite veya fragman yeniden oluşturulduğunda eski fragmanları görünüm çağrı cihazından almak için mükemmel bir cevaptır.
Smeet

7

ViewPager'den geçerli Görünür parçayı almak için . Bu basit ifadeyi kullanıyorum ve iyi çalışıyor.

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

3

Önce tüm parçaların bir listesini yaparak ele aldım (List<Fragment> fragments; kullanacağım ) sonra görüntülenen parçayı işlemeyi kolaylaştırmak için çağrı cihazına ekledim.

Yani:

@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);
}

o zaman bu çağrılabilir:

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

o zaman ben sadece doğru parçasında olsaydı çalışacak bir if ifadesinde chuck olabilir

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

ama bu sadece hack ve eğik çizgi yaklaşımım ama benim için çalıştı, geri düğmesine basıldığında şu anda görüntülenen parçamla ilgili değişiklikler yapmak için kullanıyorum.


1
benim için en iyi cevap
Sonu Kumar

3

Bu Steven'ın yukarıdaki cevabına dayanıyor. Bu, üst etkinliğe zaten eklenmiş olan parçanın gerçek örneğini döndürür.

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
                }
            }
        }
    }

2

Bunu yapmanın basit ve temiz bir yolunu bulamadım. Ancak, ViewPager widget'ı sadece parçalarınızı barındıran başka bir ViewGroup. ViewPager bu parçaları hemen çocuklar olarak kullanır. Böylece, yalnızca (.getChildCount () ve .getChildAt () kullanarak) yineleyebilir ve aradığınız parça örneğinin şu anda ViewPager'e yüklenip yüklenmediğine bakabilirsiniz. Örneğin, parçaları birbirinden ayırmak için statik benzersiz bir kimlik alanı kullanabilirsiniz.

ViewPager, ListView gibi bir sanallaştırma kapsayıcısı olduğundan aradığınız parçayı yüklememiş olabilir.


1
Yanıtınız için teşekkürler, adpter.getItem (); Android programlarında birinci sınıf öğrencisiyim. gerçekten çok minnettarım. Şimdi ListFragment alabilirsiniz ve ben footerView eklemek istiyorum, Bunu benim Aktivite yaparken o zaman logcat yazdırmak: "java.lang.IllegalStateException: İçerik görünümü henüz değil. Oluşturulan" biliyorum. Neden ama uğraşmakta zorlanıyorum Bununla.
Qun Qin

1
FragmentActivity'de onAttachFragment () yöntemi var, ViewPager beyaz parça içeriği için bu çalışmayı dozlayın?
Vasil

2

FragmentPagerAdapter parçaların fabrikasıdır. Hala hafızadaysa konumuna göre bir parça bulmak için şunu kullanın:

public Fragment findFragmentByPosition(int position) {
    FragmentPagerAdapter fragmentPagerAdapter = getFragmentPagerAdapter();
    return getSupportFragmentManager().findFragmentByTag(
            "android:switcher:" + getViewPager().getId() + ":"
                    + fragmentPagerAdapter.getItemId(position));
}

V4 desteği API'si için örnek kod.


Onresume () içinde null döndürüyor. Neden ve düzeltmek için çapa herhangi bir fikir?
seema

2

Sen yok çağrıya gerek getItem()bir referansını almak için ya da daha sonraki bir aşamada diğer bazı yöntemle Fragmentbarındırılan iç ViewPager. İçerideki bazı verileri güncellemek istiyorsanız, Fragmentbu yaklaşımı kullanın: ViewPager'i dinamik olarak güncelle?

Önemli olan, içerideki yeni verileri ayarlamak Adaperve arayacak , size bir referans gönderecek ve bunları güncelleme şansı notifyDataSetChanged()verecektir . Diğer tüm yollar, kendinize veya iyi bir çözüm olmayan başka bir saldırıya başvurmanızı gerektirir.getItemPosition()Fragment

@Override
public int getItemPosition(Object object) {
    if (object instanceof UpdateableFragment) {
        ((UpdateableFragment) object).update(xyzData);
    }
    //don't return POSITION_NONE, avoid fragment recreation. 
    return super.getItemPosition(object);
}

Burada anlamıyorum, getItemPosition () kullanmak için bir Fragment referans gerekir, bu yüzden de getItemPosition kullanmak değil, ha?

getItemPosition()adaptörünüzdeki bir yöntemdir. Doğrudan aramayacaksın. Adaptörünüzün bir referansı var, böylece adaptörünüzün referansını geçerek adaptörünüzü adapter.notifyDataSetChanged()arayacaksınız . Uygulamada tam bir uygulama görebilirsiniz burada stackoverflow.com/questions/19891828/…getItemPosition()Fragment
M-WaJeEh

Bunu okudum ve hala anlamıyorum. Onlara karşı arama yapmak için hala bu parçalara doğrudan başvurmanız gerekir, değil mi? Bunu bir hack olarak söylüyorsunuz ama alternatif görmüyorum; adaptor.getItem (i) açıkça işe yaramayacak.

2
Tamam Cevabımı daha fazla netleştirmek için güncelledim. Tabii ki bir güncelleme için bir referans gereklidir Fragmentama nasıl referans alınacağı tartışmaya açıktır. Diğer çözümler , tüm parçaların kendilerini yeniden oluşturmasına neden FragmentManagerolan "android:switcher:"+idveya buna dönen bir dize kullanarak referans alır . POSITION_NONEgetItemosition()
M-WaJeEh

Teşekkürler, bu çok daha mantıklı ve deneyimlerime uyuyor (bu yüzden yanlış bir şey yapmıyor olabilirim, ha).

2

Zorunluluk uzanır FragmentPagerAdaptersenin ViewPager adaptör sınıfa.
Eğer kullanırsanız FragmentStatePagerAdaptero zaman Fragmentonun tarafından bulamazsınız.ID

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

Bu yöntem nasıl kullanılır: -

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

2

Hey bu soruyu burada yanıtladı . Temel olarak, geçersiz kılmanız gerekir

public Object instantiateItem (ViewGroup kapsayıcısı, int konumu)

FragmentStatePagerAdapter yöntemi.


1

En iyi çözüm ziyaret ederek hazırladığımız uzantıyı kullanmaktır codepath denilen SmartFragmentStatePagerAdapter . Bu kılavuzu izleyerek, bir ViewPager öğesinden parçaların ve seçili olan parçayı almayı önemli ölçüde kolaylaştırır. Ayrıca, bağdaştırıcının içine yerleştirilmiş parçaların belleğini yönetmede daha iyi bir iş çıkarır.


0

En kolay ve en kısa yol. İçindeki tüm parçalarınız ViewPagerfarklı sınıflara aitse bunları aşağıdaki gibi alabilir ve ayırt edebilirsiniz:

public class MyActivity extends Activity
{

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

}

ViewPager kullandığınızda bağlanan birden çok parça olduğundan bu da yanlıştır. geçerli sayfa parçası var ve solunda bir tane ve sağında bir tane var. Bu, kullanıcının yalnızca kullanıcı ulaştığında başlatması gerekmeden aralarında kayabilmesini sağlar.
android geliştirici

0

Bunu biraz farklı bir yaklaşımla uyguladım.

Özel FragmentAdapter.getItem yöntemim yeni MyFragment () öğesini değil, FragmentAdapter yapıcısında oluşturulan MyFragment örneğini döndürdü.

Benim etkinliğimde daha sonra parçayı adaptörden aldım, gerekli Fragment olup olmadığını kontrol edin, sonra döküm yapın ve gerekli yöntemleri kullanın.


0

/Values/integers.xml dosyasında tamsayı kaynak kimliği oluşturma

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

Sonra PagerAdapter getItem işlevinde:

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;
        }

Sonra aktivite parçası almak için bu işlevi yazın:

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;
    }

Yukarıdaki işlevi çağırarak parça referansını alın ve ardından özel parçanıza yayınlayın:

Fragment fragment = getFragmentByPosition(position);

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

0

Fragman yöneticisinde fragmanlar üzerinde yineleme yapmanın kolay yolu. Genel statik PlaceholderFragment newInstance (int sectionNumber) içine yerleştirilen bölüm konumu bağımsız değişkeni olan viewpager'ı bulun .

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;
}

0

Parçalı

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

}

FragmentActivity'de

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();
    }
}

0

TabLayout'ta Fragment için birden fazla sekme vardır. parçanın dizinini kullanarak parçayı Etikete göre bulabilirsiniz.

Örn. Fragment1 dizini 0'dır, bu nedenle findFragmentByTag()yöntemde, Viewpager için etiketi iletin. fragmentTransaction'ı ekledikten sonra parçayı değiştirin.

String tag = "android:switcher:" + R.id.viewPager + ":" + 0; Fragment1 f = (Fragment1) getSupportFragmentManager().findFragmentByTag(tag);


-1

Adaptör için uygun FragmentStatePagerAdapter bir çözümü finanse ediyorum:

FragmentActivity'de:

ActionBar mActionBar = getSupportActionBar(); 
mActionBar.addTab(mActionBar.newTab().setText("TAB1").setTabListener(this).setTag(Fragment.instantiate(this, MyFragment1.class.getName())));
mActionBar.addTab(mActionBar.newTab().setText("TAB2").setTabListener(this).setTag(Fragment.instantiate(this, MyFragment2.class.getName())));
mActionBar.addTab(mActionBar.newTab().setText("TAB3").setTabListener(this).setTag(Fragment.instantiate(this, MyFragment3.class.getName())));

viewPager = (STViewPager) super.findViewById(R.id.viewpager);
mPagerAdapter = new MyPagerAdapter(getSupportFragmentManager(), mActionBar);
viewPager.setAdapter(this.mPagerAdapter);

ve sınıfınızda bir yöntem oluşturun FragmentActivity - Böylece bu yöntem Parçanıza erişmenizi sağlar, sadece istediğiniz parçanın konumunu vermeniz gerekir:

public Fragment getActiveFragment(int position) {
String name = MyPagerAdapter.makeFragmentName(position);
return getSupportFragmentManager().findFragmentByTag(name);
}

Adaptörünüzde:

public class MyPagerAdapter extends FragmentStatePagerAdapter {

private final ActionBar actionBar;
private final FragmentManager fragmentManager;

public MyPagerAdapter(FragmentManager fragmentManager, com.actionbarsherlock.app.ActionBarActionBar mActionBar) {super(fragmentManager);
this.actionBar = mActionBar;
this.fragmentManager = fragmentManager;
}

@Override
public Fragment getItem(int position) {
getSupportFragmentManager().beginTransaction().add(mTchatDetailsFragment, makeFragmentName(position)).commit();
return (Fragment)this.actionBar.getTabAt(position);
}

@Override
public int getCount() {
return this.actionBar.getTabCount();
}

@Override
public CharSequence getPageTitle(int position) {
return this.actionBar.getTabAt(position).getText();
}

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

}

-1
Fragment yourFragment = yourviewpageradapter.getItem(int index);

indexbağdaştırıcıdaki parçanın fragment1ilk eklediğiniz gibi olması bu nedenle geri alma fragment1geçişini index0 olarak kabul edin.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.